`set -e` を使用した Bash スクリプトが `... && ...` コマンドで停止しない

`set -e` を使用した Bash スクリプトが `... && ...` コマンドで停止しない

set -e最初のエラーでbashスクリプトを停止する

次のコマンドを使用しない限り、すべて正常に動作します&&:

$ cat script
set -e
cd not_existing_dir && echo 123
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
I'm running! =P
$

と比べて:

$ cat script
set -e
cd not_existing_dir
echo "I'm running! =P"
$
$ ./script
./script: line 2: cd: not_existing_dir: No such file or directory
$

最初の例ではまだエコーしますI'm running!が、2 番目の例ではエコーしません。なぜ動作が異なるのでしょうか?

UPD。同様の質問:https://stackoverflow.com/questions/6930295/set-e-and-short-tests

答え1

これは文書化された動作です。bash(1) マニュアルページ言う、set -e

失敗したコマンドが、whileまたはキーワードの直後のコマンドリストの一部である場合、または予約語の untilまたはの後のテストの一部である場合、シェルは終了しません。ifelif&&または||リスト内で実行されるコマンドの一部 最後&&のまたは||、パイプライン内の最後以外のコマンド、またはコマンドの戻り値が で反転されている場合!
[強調追加]

そしてそのPOSIXシェルコマンド言語仕様 これが正しい動作であることを確認します。

、、、または予約語に続く複合リスト、予約語で始まるパイプライン、または最後以外の AND-OR リストのコマンドを実行する場合、設定-eは無視されます。whileuntilifelif!

そしてセクション2.9.3リストその文書は定義している

AND-OR リストは、演算子 " &&" と " ||" で区切られた 1 つ以上のパイプラインのシーケンスです。

答え2

このset -eオプションは状況によっては効果がありませんが、これは標準的な動作であり、POSIX 準拠のシェル間で移植可能です。


失敗したコマンドはパイプラインの一部です:

false | true; echo printed

印刷されますprinted

パイプライン自体の障害のみが考慮されます。

true | false; echo 'not printed'

何も印刷されません。


while失敗したコマンドは、予約語、予約語で始まるパイプライン、または最後のコマンドを除くリストまたはリストuntilの一部である任意のコマンドに続く複合リストで実行されました。ifelif!&&||

false || true; echo printed

最後のコマンドが失敗しても、set -e影響は残ります:

true && false; echo 'not printed'

サブシェル複合コマンドで失敗します:

(false; echo 'not printed') | cat -; echo printed

答え3

私の推測では、if-then 条件全体は true と評価されます。

私は試した

set -e
if cd not_existing_dir
then  echo 123
fi
echo "I'm running! =P"

与える人

-bash: cd: not_existing_dir: No such file or directory
I'm running! =P

エラー コードは if 条件によってキャッチされるため、bash は実行の終了をトリガーしません。

関連情報