bash算術式のnullまたは設定されていない変数が0に置き換えられたと仮定しても安全ですか?

bash算術式のnullまたは設定されていない変数が0に置き換えられたと仮定しても安全ですか?

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

はい、算術拡張はから借用され、bash80年代以降にksh文書化された方法でした。ksh

ただし、POSIX算術拡張では、10進定数が含まれていない限り(、およびは大丈夫ですが空の文字列でも)$((x * 2))動作は(POSIXによって)指定されません。これは、POSIXスクリプトAssumptionsでこれを実行できないことを意味します。$x2-21+1sh

また参照してください(少なくともbash):kshzsh

$ 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

関連情報