Come rendere l'argomento opzionale in bash?


13

Nella seguente funzione con 9 argomenti:

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

Voglio fare in modo che i secondi argomenti al successivo (3..9) diventino argomenti opzionali .

Quando chiamo la funzione con 2 argomenti ottengo un errore:

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

Nota BOLD : il primo argomento e il secondo argomento sono argomenti force e non facoltativi per la funzione. Voglio solo secondi argomenti a quello successivo è facoltativo e quando chiamo la funzione meno di 2 argomenti la funzione non deve restituire alcun risultato.

Risposte:


22

Se non passerai argomenti con spazi:

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

Effetto:

$ sum 1 2 3
6

Spiegazione:

  1. <<<"some string"si "some string"inserisce solo come input. Pensalo come una scorciatoia per echo "some string" |. Si chiama Here String .
  2. "$@"si espande in tutti i parametri posizionali, separati da spazi. È equivalente a "$1 $2 ...".
  3. Quindi, tr ' ' '+' <<<"$@"output "$1+$2+$3...", che viene valutato dall'esterno $(( )).
  4. [[ -n $2 ]]verifica se il secondo parametro non è vuoto. È possibile sostituire [[ -n $2 ]] &&con [[ -z $2 ]] ||.

Un altro modo:

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

Spiegazione:

  1. $*è proprio come $@, tranne per il fatto che i parametri non sono separati da spazi, ma dal primo carattere del separatore di campo interno ( IFS) . Con IFS=+, si espande a "$ 1 + $ 2 + ...". Vedi Qual è la differenza tra $ * e $ @?
  2. Abbiamo impostato IFSuna subshell (notare le parentesi circostanti) in modo che la shell principale non sia interessata. IFSè, per impostazione predefinita: \t\n(spazio, scheda, nuova riga). Questa è un'alternativa all'utilizzo delle localvariabili.

Ora, per rispondere alla tua domanda:

È possibile utilizzare un valore predefinito per qualsiasi variabile o parametro. O:

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

O:

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

6
Nifty! So che i commenti non sono fatti per complimenti gratuiti e grazie, ma questa soluzione è solo ... malvagia! :-)
zwets,

17

Dai un'occhiata shiftall'operatore. Sposterà gli argomenti 2 e successivi alle posizioni 1 e successive, scartando l'argomento 1.

sum () {
    local total=0;
    while [ $# -gt 0 ]; do
        total=$(($total + $1))
        shift
    done
    echo $total
}

4

È possibile utilizzare una definizione ricorsiva che termina quando sumviene invocata senza argomenti. Facciamo uso del fatto che testsenza argomenti si valuta false.

sum () {
    test $1 && echo $(( $1 + $(shift; sum $@) )) || echo 0
}

3

Prova questo:

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

Questo produrrà 12 e 30.

$@si riferisce al parametro, $#restituisce il numero del parametro, in questo caso 3 o 11.

Testato su Linux Redhat 4


2

Potresti semplicemente usare un piccolo ciclo:

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

Personalmente, userei perlo awkinvece:

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

o

sum(){
 echo "$@" | awk '{for(i=1; i<=NF; i++){k+=$i} print k}'
}

2

Usa 0 come valori predefiniti da $ 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}))"
}

Da 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.

Esempi:

$ SUM

La somma è 0

$ SUM 1 2 

La somma è 3

$ SUM 1 1 1 1 1 1 1 1 1 

La somma è 9


Stesso output con awk:

SUM() {
  echo -e ${@/%/\\n} | awk '{s+=$1} END {print "The sum is " s}'
}

1

È anche la mia soluzione, l'ho provato e ho trovato:

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

$ SUM 4 6 5
The sum is 15

Ma la risposta di @ muru è buona.


+1: utilizzo interessante di due espansioni aritmetiche per valutare zero parametri vuoti.
muru

1
@muru grazie, ma in questo caso la mia risposta non usiamo più di 9 argomenti e dobbiamo usare un gruppo di argomenti per passare più di 9. Grazie per la tua risposta che è perfetta.
αғsнιη,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.