Bashで次の動作を観察します。
{ echo 'foo' ; sleep 10 ; }
-> stdout "foo"がすぐに表示され、コマンドは10秒後に完了します(予想どおり)。
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo')
-> stdout "foo"がすぐに表示され、コマンドは10秒後に完了します(予想どおり)。
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' | grep 'oo')
-> 10秒後にstdout "foo"が表示されます。
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' >&2)
-> 10秒後にstderr "foo"
コマンド置換で単一のgrepを使用するコマンドラインは結果をすぐに出力しますが、パイプとリダイレクトのあるバリエーションはスリープモードが終了するのを待つのはなぜですか?
答え1
そのように空想する必要はありません。同じ効果を観察できます。
{ echo 'foo' ; sleep 10 ; } | grep oo | grep oo
または
{ echo 'foo' ; sleep 10 ; } | grep oo | cat
または
- 2 つの端末を開きます。両方のディレクトリから同じディレクトリ(ホームディレクトリなど
/tmp
)に移動します。 - そのいずれかで行ってください
{ echo 'foo' ; sleep 10 ; } | grep oo > foo.out
。 - 一方、
ls -ld foo.out
繰り返し実行してください。ファイルはすぐに表示されますが、10秒間サイズが0で、その後4バイトの長さになる
ことがわかります。foo.out
簡単に言えば、grep
(標準)出力が端末であるかどうかをテストします。そうであれば、書かれたのと同じくらい速く出力を作成します。それ以外の場合は、出力をバッファリングして書き込みます。窒素 1バイト、ここ窒素 通常512ですが、一部の実装では異なる場合があります。
答え2
Scottの答えを拡張すると、次のようになります。
比較する
{ echo 'foo' ; sleep 3 ; } | grep oo | cat
そして
{ echo 'foo' ; sleep 3 ; } | stdbuf -o 0 grep oo | cat