引数をbashでオプションとして作成する方法は?


13

以下の9つの引数を持つ関数:

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

next(3..9)2番目の引数をオプションの引数にしたい

2つの引数で関数を呼び出すと、エラーが発生します。

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

太字:最初の引数と2番目の引数は強制引数であり、関数のオプションではありません。次の2番目の引数のみがオプションであり、2未満の引数を呼び出すと、関数は結果を返さない必要があります。

回答:


22

スペースを含む引数を渡さない場合:

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

効果:

$ sum 1 2 3
6

説明:

  1. <<<"some string""some string"入力としてのみフィードします。の省略形と考えてくださいecho "some string" |Here Stringと呼ばれます。
  2. "$@"スペースで区切られたすべての定位置パラメーターに展開されます。これはと同等"$1 $2 ..."です。
  3. したがって、tr ' ' '+' <<<"$@"outers "$1+$2+$3..."によって評価されるoutputs $(( ))
  4. [[ -n $2 ]]2番目のパラメーターが空でないかどうかをテストします。あなたは置き換えることができ[[ -n $2 ]] &&[[ -z $2 ]] ||

別の方法:

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

説明:

  1. $*$@パラメータはスペースで区切られているのではなく、内部フィールド区切りIFS文字)の最初の文字で区切られていることを除いて、と同様です。ではIFS=+、「$ 1 + $ 2 + ...」に展開されます。$ *と$ @の違いをご覧ください
  2. IFSメインシェルが影響を受けないように、サブシェルに設定します(周囲の括弧に注意してください)。IFSデフォルトでは:(\t\nスペース、タブ、改行)。これはlocal変数を使用する代わりになります。

質問に答えましょう:

任意の変数またはパラメーターにデフォルト値を使用できます。どちらか:

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

または:

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

6
気の利いた!コメントは無償の賛辞や感謝を意味するものではないことを知っていますが、この解決策はただ...邪悪です!:-)
zwets 14

17

見ていshift演算子を。引数2以降を位置1以降にシフトし、引数1を破棄します。

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

4

sum引数なしで呼び出されたときに終了する再帰的な定義を使用できます。test引数なしで評価されるという事実を利用しfalseます。

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

3

これを試して:

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

これにより、12と30が出力されます。

$@パラメータを参照し、パラメータ$#の数、この場合は3または11を返します。

Linux Redhat 4でテスト済み


2

ちょっとしたループを使うことができます:

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

個人的には、私は単にperlまたはawk代わりに使用します:

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

または

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

2

$ 1から$ 9のデフォルト値として0を使用します。

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

から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.

例:

$ SUM

合計は0

$ SUM 1 2 

合計は3です

$ SUM 1 1 1 1 1 1 1 1 1 

合計は9です


awkと同じ出力:

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

1

それは私がそれを試して見つけた私自身の解決策でもあります:

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

$ SUM 4 6 5
The sum is 15

しかし、@ muruの答えは良いです。


+1:空のパラメーターをゼロに評価するための2つの算術展開の興味深い使用法。
ムル14

1
@muruに感謝しますが、この場合 9つ以上の引数を使用しないでください。9つ以上の引数を渡すには、引数のグループを使用する必要があります。完璧な答えをありがとう。
αғsнιη
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.