パイプ 'false' はゼロ以外の結果コードを提供しません。

パイプ 'false' はゼロ以外の結果コードを提供しません。

私は以下を理解します:

true;   echo "$?"      # 0
false;  echo "$?"      # 1
true  | echo "$?"      # 0

しかし、これではありません:

false | echo "$?"      # 0

...なぜ印刷されないのですか1

パイプラインが強制的に失敗した後に回復するにはどうすればよいですか1

答え1

どちらの結果も誤解を招く可能性がtrue | echo "$?"ありますfalse | echo "$?"。内容が"$?"設定されます今後コマンドをfalseコマンドにパイプしますecho

この行を実行するために、bashはコマンドパイプラインを設定します。パイプラインが設定された後、コマンドは並列に開始されます。したがって、あなたの例では次のようになります。

true;   echo "$?"      # 0
false;  echo "$?"      # 1
true  | echo "$?"      # 0

同じです:

true   
echo "$?"      # 0
false  
echo "$?"      # 1
echo "$?"      # 0

trueecho $?同時に実行されるまで実行されません。

答え2

in false | echo $?$?終了状態ではありません。falseなぜなら$?小数点まで拡張出口最近の状況管路[1]最新ではない注文するサブシェルまたはサブプロセス。ではパイプではfalse | echo $?なくfalseパイプの一部にすぎません。シンプル十分コマンドfalse;|

set -o pipefail開いていて終了状態がfalse | echo $?終了状態であるとfalse仮定すると、$?現在のパイプがエコーされたときにまだ終了していないため、現在のパイプの状態を終了する方法もありません。

パイプの両側の順序は重要ではありません(常に並列に実行echo $?)開始または終了するか、実際にサブプロセスまたはサブシェルで実行されているか。

FWIW、サブシェルにあるときの変数およびその他のパラメータいつも現在のサブシェルのコンテキストで拡張:false | echo $?パイプの各側で別々のプロセスを分岐して実行した場合(Bashの場合ですがすべてのシェルでは該当しません)、$?サブプロセスで拡張されます。後ろにそして、fork()おそらくパイプの左側に出た後かもしれません[2]。

パイプが失敗するように強制し、1を取得するにはどうすればよいですか?

を使用すると、set -o pipefailbash、zsh、kshでサポートされ、次に含める必要があります。今後のバージョン基準。しかし、上記のように、これは単に影響を与えます。$? 後ろにパイプが出てきたが、パイプ自体の内部にはない。


[1]2.5.2 特殊パラメータSUSv4標準から。この場合、コマンド置換がパイプとして処理されるかどうかはシェルによって異なります。ほとんどの過去および現在のシェルでは:; echo `exit 13` $?印刷されますが、13一部(例:dash、yash、またはpdksh派生シェル)では印刷されます0

echo $BASHPID >&2 | echo $BASHPID >&2 | echo $BASHPID >&2[2]変数を理解するのに役立つ簡単なbashの例は次BASHPIDのとおりです。いいえ3つのサブプロセスが設定され実行される前に拡張してください。このような特殊パラメータは$?この点では特別ではありません。他の変数のように拡張されます。

答え3

これは、パイプラインの2つの部分が並列に実行されるため、falseコマンドは$?すでに印刷を開始していますが、まだ完了しておらず、設定されていないためです。echo$?より早いあなたの場合、最後のコマンドがecho実行された可能性が高くなります(そしておそらく成功したかもしれません)。

関連情報