これは、実装の選択によるものです。
ksh93
を使用して Solaris で同じスクリプトを実行する 別の動作を生成します:
$ while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
cat: write error [Broken pipe]
問題を引き起こすのは内部パイプラインです。それがなければ、シェル/OS に関係なくループが終了します:
$ while /usr/bin/true ; do echo "ok" ; done | exit 1
$
cat
bash で SIGPIPE シグナルを受信していますが、シェルはとにかくループを繰り返しています。
Process 5659 suspended
[pid 28801] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28801] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28801 detached
Process 28800 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28802 attached
Process 28803 attached
[pid 28803] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
Process 5659 suspended
[pid 28803] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28803 detached
Process 28802 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28804 attached
Process 28805 attached (waiting for parent)
Process 28805 resumed (parent 5659 ready)
Process 5659 suspended
[pid 28805] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28805] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28805 detached
Process 28804 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
バッシュ ドキュメントの状態:
<ブロック引用>シェルはすべてのコマンドを待ちます 値を返す前にパイプラインで終了します。
クシュ ドキュメントの状態:
<ブロック引用>おそらく最後のコマンドを除いて、各コマンドは個別のプロセスとして実行されます。シェルは最後のコマンドを待ちます 終了します。
POSIX 状態:
<ブロック引用>パイプラインがバックグラウンドにない場合 (非同期リストを参照)、シェルは最後のコマンドを待ちます 完了までパイプラインで指定され、すべてのコマンドを待機することもあります 完了します。
この問題は何年も私を悩ませてきました。正しい方向への微調整をしてくれた jilliagre に感謝します。
質問を少し言い換えると、私の Linux ボックスでは、これは期待どおりに終了します:
while true ; do echo "ok"; done | head
しかし、パイプを追加してもできません 期待どおり終了:
while true ; do echo "ok" | cat; done | head
それは何年も私を苛立たせました。 jilliagre によって書かれた回答を検討することによって、私はこの素晴らしい修正を思い付きました:
while true ; do echo "ok" | cat || exit; done | head
Q.E.D. ...
まあ、そうではありません。これはもう少し複雑です:
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' || exit
done | head
これはうまくいきません。 || exit
を追加しました そのため、早期に終了する方法を知っていますが、最初の echo
grep
と一致しません そのため、ループはすぐに終了します。この場合、grep
の終了ステータスにはまったく関心がありません。 .私の回避策は、別の cat
を追加することです .そこで、「tens」と呼ばれる不自然なスクリプトを次に示します:
#!/bin/bash
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' | cat || exit
done
tens | head
として実行すると、これは正しく終了します .神に感謝します。