コマンドライン引数として数値のリストを取得し、それらの数値の合計を出力するBashスクリプトを作成しようとしています。
したがって、スクリプトはscript.sh 1 555 22 122 66
として実行され、それらをすべて合計します。それらを$@
変数に渡してからループを実行する必要があることはわかっていますが、計算を行うために$@
の内容をintに変換する方法がわかりません。私はこれをやろうとしました:
#!/bin/bash
for i in $@
do
$@+$@
echo "the total is `$@`"
done
一般に、引数は、算術$((...))
展開内で使用される場合、自動的に整数に変換されます。このループはすべての引数を合計します。
for x; do sum=$((sum+x)); done; echo "$sum"
Cプログラムがargv []配列を処理するときに、シェルはすべての引数を別々のメモリ位置にキャッシュします。シェルユーザーはその配列を直接処理する必要はありません。シェルはそれらを$ 1、$ 2、$ 3などに割り当てることで役立ちます。シェルは「$ @」などのリストも抽象化します。そして最後に、構文for x
は、for x in "$@"
がすべての引数をループするための省略形です。
これは、引数がゼロで始まらない10進数、ゼロで始まる8進数、または0x
で始まる16進数であり、合計がオーバーフローしないことを前提としています(64ビットシステムでは2 ^ 63-1 )
このリスト:
$ ./script 12 021 0xab
200
(小数の結果)を出力します。
これは、次の方法で実現できます。
tr ' ' '+' <<<"$@" | bc
渡されたすべての引数を受け取り、空白を+
記号に置き換えてから、それをbc
にパイプします。
議論を一つずつ取ってください:
total=0
while [ -n "$1" ]; do
total=$((total + "$1"))
shift
done
または、for
ループを使用します:
total=0
for argument; do
total=$((total + "$argument"))
done
他の回答が使用したように$(())
に加えて、(())
を使用して、次のように内部で+=
を使用することもできます。
sum=0
for x; do
(( sum += x ))
done
echo $sum
また、提供したコードで何をしていたかを説明するのにも役立つ場合があります。基本的に、各引数を空白で分割し($@
でfor i in $@
を二重引用符で囲まなかったため)、結果をループしました。次に、行った割り当てを無視し、空白の引数をさらに2回分割し、最初のセットの最後の引数と2番目のセットの最初の引数を+
で結合し、最初の引数で指定されたコマンドを残りの引数としての引数。したがって、たとえば、このスクリプトの名前がsum
で、次のように呼び出した場合:sum "1 2" 3
、その$@+$@
は次のようにコマンド1
を呼び出そうとします(/bin/1
を探していても):1 "2" "3+1" "2" "3"
。おそらく、bash: 1: command not found
のようなbash警告が3回(引数ごとに1回)発生する可能性があります。次に、ループ内にecho
を記述したため、引数ごとに合計を1回報告しようとします。実際には、文字列のバッククォートのために、1 "2" "3"
がコマンドとして再度解釈された状態で1
を実行しようとします。これにより、コマンドが見つからなかったというbash警告も発生します。コマンドがなかったため、出力はなく、echo
は「合計は」とエコーします。したがって、完全な結果は次のとおりです。
$ sum "1 2" 3
bash: 1: command not found
bash: 1: command not found
the total is
bash: 1: command not found
bash: 1: command not found
the total is
bash: 1: command not found
bash: 1: command not found
the total is
#!/bin/sh
IFS='+'
printf '%s\n' "$*" | bc
テスト
$ ./script.sh 1 2 3 -1 30 0.1
35.1
"$*"
は、IFS
シェル変数の最初の文字で区切られた位置パラメーター(コマンドライン引数)に展開されます。 IFS
をプラス記号に設定し、評価のために文字列をbc
に渡します。
整数演算のみが必要な場合:
#!/bin/sh
IFS='+'
printf '%d\n' "$(( $* ))"