Bash'da isteğe bağlı olarak argüman nasıl yapılır?


13

Aşağıdaki 9 bağımsız değişkeni olan fonksiyon:

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

Sonraki (3..9) için ikinci argüman isteğe bağlı bir argüman haline getirmek istiyorum .

İşlevi 2 argümanla çağırdığımda hata alıyorum:

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

Not BOLD : birinci bağımsız değişken ve ikinci bağımsız değişken zorlama bağımsız değişkenleridir ve işlev için isteğe bağlı değildir. Ben sadece sonraki ikinci argüman isteğe bağlıdır ve 2 argümandan daha az fonksiyon çağırdığınızda fonksiyon sonuç vermemelidir.

Yanıtlar:


22

Boşluk içeren bağımsız değişkenler iletmezseniz:

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

Etki:

$ sum 1 2 3
6

Açıklama:

  1. <<<"some string"yalnızca "some string"girdi olarak beslenir . Bunu kısayol olarak düşünün echo "some string" |. Buraya Here String denir .
  2. "$@"boşluklarla ayrılmış tüm konum parametrelerine genişler. Eşdeğerdir "$1 $2 ...".
  3. Böylece, dış tarafından değerlendirilen tr ' ' '+' <<<"$@"çıktılar ."$1+$2+$3..."$(( ))
  4. [[ -n $2 ]]ikinci parametrenin boş olup olmadığını test eder. Sen yerini alabilir [[ -n $2 ]] &&ile [[ -z $2 ]] ||.

Diğer yol:

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

Açıklama:

  1. $*gibi olan $@parametreler boşluklarla ayrılmış uygun değildirler, fakat ilk karakter ile iç alan ayırıcı ( IFS) . İle IFS=+"$ 1 + $ 2 + ..." değerine genişler. Bkz. $ * Ve $ @ arasındaki fark nedir?
  2. Biz set IFSyüzden ana kabuk etkilenmemesini bir kabuktaki (çevreleyen parantezler unutmayın) içinde. IFSvarsayılan olarak: \t\n(boşluk, sekme, yeni satır). Bu localdeğişkenleri kullanmaya bir alternatiftir .

Şimdi sorunuzu cevaplamak için:

Herhangi bir değişken veya parametre için varsayılan bir değer kullanabilirsiniz . Ya:

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

Veya:

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

6
Şık! Yorumların ücretsiz övgü ve teşekkürler için olmadığını biliyorum, ama bu çözüm sadece ... kötü! :-)
zwets

17

shiftOperatöre bir göz atın . Bağımsız değişken 2 ve ileriye 1 ve sonraki konumlara geçer ve bağımsız değişken 1'i atar.

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

4

sumBağımsız değişkenler olmadan çağrıldığında sonlanan özyinelemeli bir tanım kullanabilirsiniz . testTartışma olmadan değerlendirilen gerçeği kullanırız false.

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

3

Bunu dene:

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

Bu çıkış 12 ve 30'u verir.

$@"Parametre", parametreye karşılık gelir, parametre $#sayısını, bu durumda 3 veya 11 döndürür.

Linux redhat 4 üzerinde test edildi


2

Sadece küçük bir döngü kullanabilirsiniz:

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

Şahsen olsa, ben sadece kullanmayı tercih ediyorum perlya awkyerine:

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

veya

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

2

$ 1 ila $ 9 için varsayılan değerler olarak 0 kullanın:

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

Gönderen 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.

Örnekler:

$ SUM

Toplam 0

$ SUM 1 2 

Toplam 3

$ SUM 1 1 1 1 1 1 1 1 1 

Toplam 9


Awk ile aynı çıktı:

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

1

Aynı zamanda kendi çözümümü denedim ve buldum:

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

$ SUM 4 6 5
The sum is 15

Ama @ muru'nun cevabı iyi.


+1: Boş parametreleri sıfıra değerlendirmek için iki aritmetik genişletmenin ilginç kullanımı .
muru

1
muru teşekkürler, ama bu durumda cevabım 9'dan fazla argüman kullanmıyoruz ve 9'dan fazla geçmek için argüman grubunu kullanmalıyız. Mükemmel cevabınız için teşekkür ederim.
αғsнιη
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.