Bashのマニュアルページ(バージョン4.2)の算術評価セクションで、次の説明が見つかりました。
nullまたは設定されていないシェル変数は、パラメータ拡張構文を使用せずに名前で参照すると0に評価されます。
高度な Bash スクリプトガイドには次のものがあります。ページそして次のコメントを残してください。
# Bash (usually) sets the "integer value" of null to zero
#+ when performing an arithmetic operation.
# But, don't try this at home, folks!
# It's undocumented and probably non-portable behavior.
以下は、この動作の例です。
$ foo=
$ let 'foo += 5'
$ echo $foo
5
$ unset foo
$ let 'foo += 2'
$ echo $foo
2
bashがnull変数を0に置き換えると仮定しても安全ですか?これにより、bashバージョン間でコードを移植できなくなるとしましょう。
答え1
はい、算術拡張はから借用され、bash
80年代以降にksh
文書化された方法でした。ksh
ただし、POSIX算術拡張では、10進定数が含まれていない限り(、およびは大丈夫ですが空の文字列でも)$((x * 2))
動作は(POSIXによって)指定されません。これは、POSIXスクリプトAssumptionsでこれを実行できないことを意味します。$x
2
-2
1+1
sh
また参照してください(少なくともbash
):ksh
zsh
$ echo $((2*$foo-2)) # actually $((2*-2))
-4
$ echo $((2*foo-2)) # actually $((2*0-2))
-2
答え2
~から手動:
nullまたは設定されていないシェル変数は、パラメータ拡張構文を使用せずに名前で参照すると0に評価されます。
pdksh、ksh93、dash、zsh のように、これが変更されたことはわかりませんが、POSIX は動作を指定しません。
if set -o nounset
(aka set -u
)が機能して$((a))
いるか設定されていないとエラーが発生することに注意してください((a+=1))
(bashとksh93では、dash、pdksh、またはzshではありません)。a
また、$((a+1))
パラメータ置換を使用する場合は機能せず、算術式で直接パラメータを使用する場合にのみ機能します$(($a+1))
。比較:
$ unset a
$ echo $((1 - a + 2)) # 1 - 0 + 2
3
$ echo $((a - $a + 2)) # 1 - (+2)
-1
答え3
合理的に新しいシステムでは、bashがnull変数を0に置き換えると仮定するのは安全です。
bash 4.2のマンページに文書化されているように、これは少なくともそのバージョンの文書化された動作であることは明らかです。 Advanced Bash Scripting Guideで説明されているように(文書化されていない)、この動作は、このガイドが作成されたときに利用可能なすべてのバージョンのBashで期待できます。おそらくbashの初期バージョンに戻ります。
ただし、絶対に厳しくなるには、サポートするすべてのbashバージョンのドキュメントを確認する必要があり、動作が明示的に文書化されていないバージョンについては何も想定できません。
絶対に厳密である必要はないと思いますが、リスクを取る必要がない場合は、未定義foo=${foo:-0}
の変数を使用する前に明示的にゼロに設定できます。例:
foo=1
foo=${foo:-0}
bar=${bar:-0}
echo "before math: foo=$foo, bar=$bar"
let 'foo += 2'
let 'bar += 2'
echo "after math: foo=$foo, bar=$bar"
出力:
before math: foo=1, bar=0
after math: foo=3, bar=2