GNU/Linux >> Linux の 問題 >  >> Linux

終了したサブコマンドにパイプするときに bash while ループが終了しないのはなぜですか?

これは、実装の選択によるものです。

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 として実行すると、これは正しく終了します .神に感謝します。


Linux
  1. 履歴を参照すると、Bashプロンプトがバグになるのはなぜですか?

  2. プロセスが終了したときのデフォルトの終了コード?

  3. 実行後にBashスクリプトが終了しないのはなぜですか?

  1. Bash の For ループと While ループの例

  2. xargs -L では正しいフォーマットが生成されるのに、xargs -n では生成されないのはなぜですか?

  3. Bash while ループで and を使用する

  1. このシェル パイプラインが終了するのはなぜですか?

  2. bashでループの終了ステータスを取得する方法

  3. Bash:子スクリプトが SIGINT をトラップするときに親スクリプトが SIGINT で終了しないのはなぜですか?