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

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

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

#!/bin/bash -e

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

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

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

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

答え1

Failed複合コマンドの終了ステータスは、で実行された最後のコマンドの終了ステータスであるため、印刷されません{ ...; }echoSuccessechoなので、複合コマンドは終了状態 0 で終了します。

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

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

~からPOSIX規格:

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


ここではさまざまなことが起こっています(要約)。

  • あなたはset -e積極的に走っています。コマンドがゼロ以外の終了状態を返す場合(代替として)、シェルは終了します。ただし、コマンドは(リストの一部であるwill_fail複合コマンド)の一部であるため(そしてリストの最後のコマンドではないため)、これには適用されません。||

    また、POSIX規格(私のハイライト):

    予約語の後に、、、、または複合リストを実行するとき-e、予約語で始まるパイプ、またはwhileuntilifelif!どんな命令でも最後の項目を除くAND-ORのリスト。

  • リストの最後の簡単なコマンド||はですecho "Failed"。これは、複合コマンドの完全終了状態を決定します。正常に実行されたため(そしてwill_failシェルが終了していないため)、状態はゼロになり、これは反対側の端が||実行されないことを意味します。

答え2

私の考えでは紹介する許可された回答(+1徹底のために編集したにもかかわらず)は誤解を招く可能性があり、存在する場合は正確な問題を説明しませんset -e。下の行の残りの部分に答えが含まれています。私は直接ここに来て、もともと間違った情報を受け取ったので、書くことにしました。

複合コマンドの終了状態は{...;内で実行された最後のコマンドの終了状態であるため、失敗は印刷されません。 }、これはエコーです。 echo が成功したため、複合コマンドは終了状態 0 で終了します。

最初に渡す必要があるのはここset -eから場所{ ... }リストのAND-ORです。部品が取り外されると、部品が故障した直後に|| echo "Failed"複合コマンドが{ ... }中断されます。最終注文もできませんでした。{ ... }

比較する

#!/bin/bash -e

{ 
    echo "Doing something"; 
    false
    echo "Worked"; 
}

その後、何も印刷せずにエラーDoing somethingで終了します。しかし、(これが答えが間違っている理由です)内部の最後の複合{ ... }コマンドですecho

しかし、

#!/bin/bash -e

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

Worked印刷後、Doing something呼び出しは行われず、終了echo "Failed"ステータス0が返されます。

理由引用符で埋められている(許可された回答でより詳細に提供されています):set -eはい障害のあるAND-ORコマンドの一部であるすべて。

末尾の場合はAND-ORコマンドの一部になるので従順を中断|| echo "Failed"します。途中はフローに影響を与えずに進み、AND-ORに0を返して呼び出しスクリプトに戻ります。{...}set -efalseecho "Worked"

後続のコマンドがない場合、それ自体は|| echo "Failed"一般{ ... }的な複合コマンドのセットであり、POSIXで述べられている例外に該当せずに準拠していますset -e。その部分に達すると実行が停止falseし、実行フローがその部分に達していなくてもecho "Worked"呼び出しスクリプトにエラーが返されます。

関連情報