Como tornar o argumento opcional no bash?

13

Abaixo da função com 9 argumentos:

SUM() { 
    echo "The sum is $(($1+$2+$3+$4+$5+$6+$7+$8+$9))"
}

Eu quero fazer com que os segundos argumentos para o próximo (3..9) se tornem argumentos opcionais .

Quando eu chamo a função com 2 argumentos, recebo um erro:

SUM 3 8
bash: 3+8+++++++: syntax error: operand expected (error token is "+")

Nota BOLD : o primeiro argumento e o segundo argumento são force arguments e não são opcionais para a função. Eu só quero segundos argumentos para o próximo é opcional e quando eu chamo a função menos de 2 args a função deve retornar nenhum resultado.

    
por devWeek 10.09.2014 / 09:43

7 respostas

22

Se você não transmitir argumentos com espaços:

sum() {  
[[ -n $2 ]] && echo $(( $(tr ' ' '+' <<<"$@") ))
}

Efeito:

$ sum 1 2 3
6

Explicação:

  1. <<<"some string" alimenta apenas "some string" como entrada. Pense nisso como um atalho para echo "some string" | . Ele é chamado de String aqui .
  2. "$@" se expande em todos os parâmetros posicionais, separados por espaços. É equivalente a "$1 $2 ..." .
  3. Assim, tr ' ' '+' <<<"$@" outputs "$1+$2+$3..." , que é avaliado pelo% externo$(( )).
  4. [[ -n $2 ]] testa se o segundo parâmetro não está vazio. Você pode substituir [[ -n $2 ]] && por [[ -z $2 ]] || .

Outra maneira:

sum() {
[[ -n $2 ]] && (IFS=+; echo $(( $* )))
}

Explicação:

  1. $* é igual a $@ , exceto que os parâmetros não são separados por espaços, mas pelo primeiro caractere do Separador de Campo Interno ( IFS ) . Com IFS=+ , ele se expande para "$ 1 + $ 2 + ...". Veja Qual é a diferença entre $ * e $ @?
  2. Definimos IFS em um subshell (observe os parênteses ao redor) para que o shell principal não seja afetado. IFS é, por padrão: \t\n (espaço, tabulação, nova linha). Esta é uma alternativa ao uso de variáveis local .

Agora, responda sua pergunta:

Você pode usar um valor padrão para qualquer variável ou parâmetro. Qualquer um:

SUM() { 
 echo "The sum is $(($1+$2+${3:-0}+${4:-0}+${5:-0}+${6:-0}+${7:-0}+${8:-0}+${9:-0}))" || false
}

Ou:

SUM() { 
 echo "The sum is $(($1+$2+${3:=0}+${4:=0}+${5:=0}+${6:=0}+${7:=0}+${8:=0}+${9:=0}))" || false
}
    
por muru 10.09.2014 / 10:41
17

Dê uma olhada no operador shift . Ele irá mudar os argumentos 2 e para as posições 1 e seguintes, descartando o argumento 1.

sum () {
    local total=0;
    while [ $# -gt 0 ]; do
        total=$(($total + $1))
        shift
    done
    echo $total
}
    
por zwets 10.09.2014 / 10:36
4

Você pode usar uma definição recursiva que termina quando sum é invocado sem argumentos. Usamos o fato de que test sem argumentos é avaliado como false .

sum () {
    test $1 && echo $(( $1 + $(shift; sum $@) )) || echo 0
}
    
por zwets 10.09.2014 / 11:31
3

Tente isto:

SUM () {
 [ $# -lt "2" ] && return 1
 for par in $@; do
   local sum='expr $sum + $par'
 done
 echo $sum
 return 0
}

SUM 3 4 5
SUM 3 4 5 1 1 1 1 2 3 4 5

Isso produzirá 12 e 30.

$@ refere-se ao parâmetro, $# retorna o número do parâmetro, neste caso 3 ou 11.

Testado no linux redhat 4

    
por Lety 10.09.2014 / 10:06
2

Você pode usar apenas um pequeno loop:

sum(){
    t=0;
    for i in "$@"; do t=$((t + i )); done
    echo $t;
}

Pessoalmente, eu usaria apenas perl ou awk :

sum(){
 echo "$@" | perl -lane '$s+=$_ for @F; print $s'
}

ou

sum(){
 echo "$@" | awk '{for(i=1; i<=NF; i++){k+=$i} print k}'
}
    
por terdon 13.09.2014 / 15:38
2

Use 0 como valores padrão de $ 1 a $ 9:

SUM() { 
    echo "The sum is $((${1:-0}+${2:-0}+${3:-0}+${4:-0}+${5:-0}+${6:-0}+${7:-0}+${8:-0}+${9:-0}))"
}

De man bash :

${parameter:-word}
    Use Default Values. If parameter is unset or null, the expansion
    of word is substituted. Otherwise, the value of parameter is
    substituted.

Exemplos:

$ SUM

A soma é 0

$ SUM 1 2 

A soma é 3

$ SUM 1 1 1 1 1 1 1 1 1 

A soma é 9

Mesma saída com awk:
SUM() {
  echo -e ${@/%/\n} | awk '{s+=$1} END {print "The sum is " s}'
}
    
por Cyrus 10.10.2014 / 20:47
1

Também é minha própria solução que tentei e encontrei:

SUM() { 
    echo "The sum is $(($1+$2+$[$3]+$[$4]+$[$5]+$[$6]+$[$7]+$[$8]+$[$9]))"
 }

$ SUM 4 6 5
The sum is 15

Mas @ muru's answer é bom.

    
por devWeek 10.09.2014 / 11:26