Bash:「読み込み中」プロセス置換操作がパイプから抜け出すことはできません。

Bash:「読み込み中」プロセス置換操作がパイプから抜け出すことはできません。

私はプログラムの出力をwhile read VARループにパイプし、パターンがbreak見つかったら出力する予定でしたが、そうではありませんでした。

概念の証拠:

inotifywait -qm -e create . | while read line; do echo $line; break; done
./ CREATE newfile

..

tail -f /var/log/syslog | while read line; do echo $line; break; done
Nov 6 22:44:05 section9 ntpdate[2381]: adjust time server 91.189.89.199 offset 0.272779 sec

ソースプログラムが何を出力しても終了しません。プリセットは、set -xループが2回目以降繰り返されないことを示しますread$BASH_SUBSHELLこの例では 1 です。

tailinotifywaitなど。 SIGPIPEを受けて終了してはいけませんか?

プロセス置換(while read ... break; done < <(tail -f ...))が正しく機能することに注意してください。$BASH_SUBSHELLこの場合は0です。

答え1

要点は、bash(他のシェルは異なる場合があります)からパイプが終了するまで終了しないことです。すべてのコマンドパイプラインで完了しました。

理解するために、次の点を考えてみましょう。

inotifywait -qm -e create . | while read line; do echo $line; break; done

1行を読み取ると、readエコーされた後にbreak実行され、最後にプロセスが終了します。ただし、最初のプロセスは標準出力書き込みに失敗するまで続きます。したがって、ループは少なくともinotifywaitそのエントリに書き込もうとするまで続きます。第二出力ライン。バッファリングの曖昧さのためにこれは起こらないかもしれません。検索が発生するには複数行が必要な場合があります。書き込み試行が失敗すると、SIGPIPE が発行されます。

今、別のシナリオを考えてみましょう。

while read line; do echo $line; break; done < <(inotifywait -qm -e create .)

ここにパイプはありません。break実行するとwhileループが完了します。

文書

「パイプライン」セクションでman bash

シェルすべてのコマンドを待ちますパイプからシャットダウン中...

これはあなたがする選択ですbash。 POSIXではこれを義務付けていません。 POSIX状態:

パイプがバックグラウンドにない場合(非同期リストを参照)、シェルはパイプで指定された最後のコマンドが完了するまで待つ必要があります。待つことができるすべてのコマンドを完了するには

答え2

strace tail -f -n 5000 /var/log/messages | 
    while read line; do echo $line; break; done;

何が起こったのかを詳しく見せてください。

[...]
write(1, "Nov  1 22:20:01 inno systemd[1]:"..., 4096) = 4096

つまり、tailは一度に最大4096バイトをパイプに書き込むことができます(パイプがバッファリングできる容量)。データがあまり多くない場合が多いですtail

strace tail -f /var/log/messages | while read line; do echo $line; break; done;

プログラム

write(1, "Nov  7 07:00:02 inno systemd[1]:"..., 730) = 730

したがって、tailファイルに何かが追加されるまで書き換えを試みません。

私はunbufferこれが解決できると思いました。そうではないことに驚きました。

unbuffer tail -f file1 | while read line; do echo $line; break; done

関連情報