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

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

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

関連情報