web-dev-qa-db-ja.com

コマンド置換内のパイプ/リダイレクトをブロック/非ブロック

私は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を含むコマンドラインが結果をすぐに出力するのに、パイプとリダイレクトを含むバリアントがスリープが終了するまで待機するのはなぜですか?

3
user19426

そんなに空想する必要はありません。あなたは同じ効果を観察することができます

{ echo 'foo' ; sleep 10 ; } | grep oo | grep oo

または

{ echo 'foo' ; sleep 10 ; } | grep oo | cat

または

  • 2つの端子を開きます。両方の同じディレクトリに移動します(例:ホームディレクトリ、または/tmp)。
  • 1つは、{ echo 'foo' ; sleep 10 ; } | grep oo > foo.out
  • もう1つは、ls -ld foo.out繰り返し。
    foo.outファイルはすぐに表示されますが、10秒間はサイズ0で、その後4バイトの長さになります。

簡単に言うと、grepは、その(標準)出力が端末であるかどうかをテストします。そうである場合は、書き込む出力と同じ速さで出力を書き込みます。そうでない場合は、出力をバッファリングし、一度に[〜#〜] n [〜#〜]バイトを書き込みます。ここで、[〜#〜] n [〜# 〜]は通常512ですが、実装によっては異なる場合があります。

3
Scott

スコットの答えを拡張する:

比較する

 { echo 'foo' ; sleep 3 ; } | grep oo | cat

 { echo 'foo' ; sleep 3 ; } | stdbuf -o 0 grep oo | cat
1
Hauke Laging