私はbashで次の動作を観察しました:
{ echo 'foo' ; sleep 10 ; }
->標準出力「foo」がすぐに表示され、10秒後にコマンドが実行されます(期待どおり)
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo')
->標準出力「foo」がすぐに表示され、10秒後にコマンドが実行されます(期待どおり)
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' | grep 'oo')
->標準出力「foo」が10秒後に表示されます
{ echo 'foo' ; sleep 10 ; } > >(grep 'oo' >&2)
->標準エラー「foo」が10秒後に表示されます
コマンド置換に単一のgrepを含むコマンドラインが結果をすぐに出力するのに、パイプとリダイレクトを含むバリアントがスリープが終了するまで待機するのはなぜですか?
そんなに空想する必要はありません。あなたは同じ効果を観察することができます
{ echo 'foo' ; sleep 10 ; } | grep oo | grep oo
または
{ echo 'foo' ; sleep 10 ; } | grep oo | cat
または
/tmp
)。{ echo 'foo' ; sleep 10 ; } | grep oo > foo.out
。ls -ld foo.out
繰り返し。foo.out
ファイルはすぐに表示されますが、10秒間はサイズ0で、その後4バイトの長さになります。簡単に言うと、grep
は、その(標準)出力が端末であるかどうかをテストします。そうである場合は、書き込む出力と同じ速さで出力を書き込みます。そうでない場合は、出力をバッファリングし、一度に[〜#〜] n [〜#〜]バイトを書き込みます。ここで、[〜#〜] n [〜# 〜]は通常512ですが、実装によっては異なる場合があります。
スコットの答えを拡張する:
比較する
{ echo 'foo' ; sleep 3 ; } | grep oo | cat
と
{ echo 'foo' ; sleep 3 ; } | stdbuf -o 0 grep oo | cat