web-dev-qa-db-ja.com

||と一緒に使用すると、この複合コマンド{...}がエラー時に終了しないのはなぜですか?

私はこのスクリプトを実行しようとしています:

#!/bin/bash -e

{ 
    echo "Doing something"; 
    will_fail                 # like `false` 

    echo "Worked"; 
} || echo "Failed"

驚いたことに、will_failは失敗しましたが、コマンドラインに「Failed」と表示されず、「Worked」と表示されました。

will_failが失敗した後、複合コマンドがエラーで終了しなかったのはなぜですか?

4
Minix

複合コマンドの終了ステータスは、{ ...; }で実行されている最後のコマンドの終了ステータス(Failed)であるため、echoは出力されません。 echoは成功するため、複合コマンドは終了ステータスがゼロで終了します。

以下は3つの文字列を出力します。

{ echo "Do something"; echo "Worked"; false; } || echo "Failed"

から POSIX標準

特に明記されていない限り、コマンドの終了ステータスは、コマンドによって実行された最後の単純なコマンドの終了ステータスになります。


ここで起こっていることがいくつかあります(要約):

  • set -eをアクティブにして実行します。これにより、コマンドがゼロ以外の終了ステータスを返した場合(大まかに言えば)、シェルが終了します。ただし、will_failコマンドは||リストの一部(一部である複合コマンド)であるため、ここでは適用されません(最後ではありません)。

    繰り返しますが、 POSIX標準 (私の強調)から:

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

  • ||リストの最後の単純なコマンドはecho "Failed"です。これが、複合コマンドの全体的な終了ステータスを決定するものです。正常に実行されるため(また、will_failによってシェルが終了しないため)、ステータスはゼロになります。これは、||の反対側が実行されないことを意味します。

11
Kusalananda