Bagaimana menjadikan argumen sebagai opsional dalam bash?


13

Dalam fungsi di bawah ini dengan 9 argumen:

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

Saya ingin membuat argumen kedua ke yang berikutnya (3..9) menjadi argumen opsional .

Ketika saya memanggil fungsi dengan 2 argumen, saya mendapatkan kesalahan:

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

Catatan BOLD : argumen pertama dan argumen kedua adalah argumen paksa dan bukan opsional untuk fungsi. Saya hanya ingin argumen kedua ke yang berikutnya adalah opsional dan ketika saya memanggil fungsi kurang dari 2 argumen fungsi harus mengembalikan hasil.

Jawaban:


22

Jika Anda tidak akan memberikan argumen dengan spasi:

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

Efek:

$ sum 1 2 3
6

Penjelasan:

  1. <<<"some string"umpan hanya "some string"sebagai input. Anggap saja sebagai singkatan echo "some string" |. Ini disebut String Di Sini .
  2. "$@"meluas ke semua parameter posisi, dipisahkan oleh spasi. Ini setara dengan "$1 $2 ...".
  3. Oleh karena itu, tr ' ' '+' <<<"$@"output "$1+$2+$3...", yang dievaluasi oleh luar $(( )).
  4. [[ -n $2 ]]menguji apakah parameter kedua tidak kosong. Anda bisa menggantinya [[ -n $2 ]] &&dengan [[ -z $2 ]] ||.

Cara lain:

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

Penjelasan:

  1. $*hanya seperti $@, kecuali bahwa parameter tidak dipisahkan oleh spasi, tetapi oleh karakter pertama Pemisah Bidang Internal ( IFS) . Dengan IFS=+, itu diperluas menjadi "$ 1 + $ 2 + ...". Lihat Apa perbedaan antara $ * dan $ @?
  2. Kami memasang IFSsubkulit (perhatikan tanda kurung di sekitarnya) sehingga shell utama tidak terpengaruh. IFSsecara default: \t\n(spasi, tab, baris baru). Ini adalah alternatif untuk menggunakan localvariabel.

Sekarang untuk menjawab pertanyaan Anda:

Anda dapat menggunakan nilai default untuk variabel atau parameter apa pun. Antara:

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

Atau:

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

6
Bagus! Saya tahu komentar tidak dimaksudkan untuk pujian dan terima kasih gratis, tetapi solusi ini hanya ... jahat! :-)
zwets

17

Lihatlah shiftoperatornya. Ini akan menggeser argumen 2 dan seterusnya ke posisi 1 dan seterusnya, membuang argumen 1.

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

4

Anda bisa menggunakan definisi rekursif yang berakhir ketika sumdipanggil tanpa argumen. Kami menggunakan fakta yang testtanpa argumen dievaluasi false.

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

3

Coba ini:

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

Ini akan menghasilkan 12 dan 30.

$@merujuk ke parameter, $#mengembalikan jumlah parameter, dalam hal ini 3 atau 11.

Diuji di linux redhat 4


2

Anda bisa menggunakan loop kecil:

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

Secara pribadi, saya hanya menggunakan perlatau awksebagai gantinya:

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

atau

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

2

Gunakan 0 sebagai nilai default untuk $ 1 hingga $ 9:

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

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

Contoh:

$ SUM

Jumlahnya adalah 0

$ SUM 1 2 

Jumlahnya adalah 3

$ SUM 1 1 1 1 1 1 1 1 1 

Jumlahnya adalah 9


Output yang sama dengan awk:

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

1

Ini juga solusi saya sendiri, saya mencobanya dan menemukan:

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

$ SUM 4 6 5
The sum is 15

Tapi jawaban @ muru bagus.


+1: Penggunaan dua ekspansi aritmatika yang menarik untuk mengevaluasi parameter kosong menjadi nol.
muru

1
@muru terima kasih, tetapi dalam hal ini jawaban saya, kami tidak menggunakan lebih dari 9 argumen dan kami harus menggunakan kelompok argumen untuk melewati lebih dari 9. terima kasih atas jawaban Anda yang sempurna.
αғsнιη
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.