シェルスクリプトはbashを使用して実行されますが、shは使用しません。理由と回避策は何ですか?

シェルスクリプトはbashを使用して実行されますが、shは使用しません。理由と回避策は何ですか?

渡されたすべての引数を要約する次のシェルスクリプトがあります(スペースで区切られています)。

sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

として保存しましたSumAll.sh。したがって、次のように動作する必要があります。

sh SumAll.sh 2 4 6 8
20

または

bash SumAll.sh 1 -2 3 -3
-1

どちらも私のローカルコンピュータ(MacBook)で動作しますが、Linuxサーバーで同じことを試みると、動作しますがbash動作shしないスクリプトを実行します。次のエラーが発生します。

sum: '+=': No such file or directory
sum: arg: No such file or directory

なぜそんなことですか?どうすれば解決できますか?

答え1

算術評価は、(( ... ))実装された標準のPOSIXシェル構文の拡張ですbash。ほとんどのshシェルはこの構文を理解していません。

代わりに算術置換を使用してください。sum=$(( sum + arg ))

非標準を実装していないシェルでは、コマンドはネストされた(( ... ))サブシェル(( sum += arg ))として解釈され、sum2つの引数+=で呼び出されますarg

macOSにはsumファイルのチェックサムを計算するユーティリティがあります(参照)ファイルが見つかりませんman sum(これが特定のエラーが発生する理由です)。+=arg

答え2

使用住宅検査

スクリプトを使用した例:

#!/bin/bash
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

結果:

$ shellcheck myscript

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

ご覧のとおり、これは機能しますが、以前と同じようにshを使用している場合:

#!/bin/sh
sum=0
for arg in "$@"; do
    (( sum += arg ))
done
echo $sum

結果:

$ shellcheck myscript

Line 4:
    (( sum += arg ))
    ^-- SC2039: In POSIX sh, standalone ((..)) is undefined.

Line 6:
echo $sum
     ^-- SC2086: Double quote to prevent globbing and word splitting.

Did you mean: (apply this, apply all SC2086)
echo "$sum"

SC2039エラー(この場合は最初のエラー)のため、ここでは機能しません。

当然ですが、これを念頭に置く必要があり、sh構文bashにはいくつかの違いがあります。これがうまくいかない主な理由です。 (@kusalanandaは彼の答えで詳しく説明されています)

-xまた、スクリプトがいつ失敗するかを確認できるようにするか、デバッグフラグをより頻繁に使用する必要があります。

Bash とシェルスクリプトの詳細情報とヒントについては、以下をお勧めします。

-Bashの非公式Wiki

-バッシュ聖書

関連情報