最近、次のスクリプトが見つかりました。
( set -e ; do-stuff; do-more-stuff; ) || echo failed
私が見るのは大丈夫に見えますが、うまくいきません!set -e
追加時には適用されません||
。それがなければうまくいきます。
$ ( set -e; false; echo passed; ); echo $?
1
||
ただし、: を追加するとset -e
無視されます。
$ ( set -e; false; echo passed; ) || echo failed
passed
実際のスタンドアロンシェルを使用すると、期待どおりに機能します。
$ sh -c 'set -e; false; echo passed;' || echo failed
failed
私はこれをいくつかの異なるシェル(bash、dash、ksh93)で試してみましたが、すべて同じように動作するので、バグではありません。誰かがこれを説明できますか?
ベストアンサー1
~によるとこのスレッドset -e
、これはサブシェルで ""を使用するためのPOSIX指定の動作です。
(私も驚きました。)
まず、行動は次のとおりです。
-e
!で始まるパイプに対してwhile、Until、if、またはelifの予約語の後にある複合リストを実行するときは、この設定は無視する必要があります。予約語またはAND-ORリストの最後の項目を除くすべてのコマンド。
2番目の記事では、次のように言います。
とにかく(サブシェルコード)で-eを設定すると、周囲のコンテキストとは無関係に動作しませんか?
習慣。 POSIXの説明は、周囲のコンテキストがサブシェルでset -eが無視されるかどうかに影響を与えることを明らかにします。
エリック・ブレイクが書いた4番目の記事では、より多くの内容を見ることができます。
ポイント3はいいえ無視されたコンテキストをオーバーライドするようにサブシェルに要求します
set -e
。つまり、-e
無視されたコンテキストにある場合何もない-e
サブシェルでもまた従順を得るためにできることがあります。$ bash -c 'set -e; if (set -e; false; echo hi); then :; fi; echo $?' hi 0
これを2回呼び出しても(親シェルとサブシェルで)、サブシェルが無視されたコンテキスト(ifステートメントの条件)
set -e
に存在するため、サブシェルでそれを再度有効にするために何もできません。-e
-e
この行動は本当に素晴らしいです。これは直観に反します。再度有効にすると効果があると予想される可能性set -e
があり、周囲の環境が優先されることはなく、POSIX標準の表現ではこれを明確に示していません。コマンドが失敗した場合に読んだ場合、このルールは適用されません。周辺コンテキストにのみ適用されますが、全体的に適用されます。