私はこれらを理解しています:
true; echo "$?" # 0
false; echo "$?" # 1
true | echo "$?" # 0
しかし、これではありません:
false | echo "$?" # 0
...なぜ表示されないのですか1
?
そして、どうすればパイプで障害を強制し、1
その後?
true | echo "$?"
とfalse | echo "$?"
の両方の結果は誤解を招く可能性があります。 "$?"
の内容が設定されますbeforeコマンドfalse
をコマンドecho
にパイプします。
これらの行を実行するために、bashはコマンドのパイプラインをセットアップします。パイプラインがセットアップされ、コマンドが並行して開始されます。だからあなたの例では:
true; echo "$?" # 0
false; echo "$?" # 1
true | echo "$?" # 0
と同じです:
true
echo "$?" # 0
false
echo "$?" # 1
echo "$?" # 0
true
はecho $?
の前に実行されず、同時に実行されます。
_false | echo $?
_では、_$?
_はfalse
の終了ステータスではありません。これは、_$?
_が10進数に展開されるためですexit =最新のステータスパイプライン[1]、最新のステータスではないコマンド、サブシェルまたは子プロセス。 _false | echo $?
_では、false
はパイプラインではなく、パイプラインの一部です。 _false;
_が含まれていない場合でも、_|
_のような単純なcompleteコマンドはパイプラインです。
_set -o pipefail
_がオンであり、_false | echo $?
_の終了ステータスがfalse
の終了ステータスであると仮定すると、_$?
_も現在のパイプラインのステータスを終了できませんでした。パイプラインは、エコーするまでにまだ終了していません。
パイプラインの両側(常に並行して実行される)が開始または終了される順序、または_echo $?
_は実際には子プロセスまたはサブシェルで実行されます。
FWIW、サブシェルの場合、変数とその他のパラメーターはalwaysが現在のサブシェルのコンテキストで展開されます:_false | echo $?
_がパイプラインの両側に別々のプロセスをフォークすることで実装されている場合(これはすべてのシェルではなくbashの場合)、_$?
_は子プロセスで展開されますafterfork()
、そしておそらくパイプラインの左側が出た後[2]。
そして、どうすればパイプで障害を強制し、その後1を取得できますか?
_set -o pipefail
_を使用します。これは、bash、zsh、kshでサポートされており、標準の 将来のバージョン に含める必要があります。しかし、上記で説明したように、これは_$?
_ afterの値にのみ影響します。パイプライン自体ではなく、パイプラインが終了しました。
[1] 2.5.2特殊パラメータ SUSv4標準。このコンテキストでコマンド置換がパイプラインと見なされるかどうかは、シェルに依存します。ほとんどの歴史的および現在のシェルでは_:; echo `exit 13` $?
_は_13
_を出力しますが、一部の(ダッシュ、yash、またはpdkshから派生した)シェルでは_0
_を出力します。
[2]これを理解するのに役立つ単純なbashの例は_echo $BASHPID >&2 | echo $BASHPID >&2 | echo $BASHPID >&2
_です。 BASHPID
変数はnotであり、3つの子プロセスが設定されて実行される前に展開されます。 _$?
_のような特別なパラメーターは、この点で特別ではありません。他の変数と同様に展開されます。
これは、パイプの両方の部分が並行して実行されるため、false
コマンドがまだ完了していない(そして$?
)echo
コマンドがすでに印刷を開始している場合$?
、これはpreviousコマンドの結果です。あなたの場合、おそらく最後に実行されたecho
(そしておそらくそれは成功したでしょう)。