web-dev-qa-db-ja.com

EOF catを介してパイプされる場合まで、grepは出力しません

この最小限の例を考えると

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )

LINE 1を出力し、1秒後にLINE 2期待どおりを出力します。


これをgrep LINEにパイプすると

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE

動作は前のケースと同じです予想どおり


あるいは、これをcatにパイプする場合

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat

動作も同じです期待どおり


ただしgrep LINEにパイプし、次にcatにパイプすると、

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat

1秒が経過するまで出力はありません。両方の行がすぐに出力に表示されます期待していませんでした


なぜこれが起こっているのですか?最後のバージョンを最初の3つのコマンドと同じように動作させるにはどうすればよいですか?

19
lisyarus

(少なくともGNU)grepの出力がターミナルではない場合、それは出力をバッファリングします。これが、表示されている動作の原因です。 GNU grep 's --line-bufferedオプション:

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat

またはstdbufユーティリティ:

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat

パイプでのバッファリングをオフにする このトピックに関する詳細があります。

38
Stephen Kitt

簡単な説明

多くのユーティリティと同様に、これは1つのプログラムに固有のものではありません。grepは、標準出力をline buffered完全にバッファリング。前者の場合、Cライブラリは、出力データを保持するバッファーがいっぱいになるか、改行文字が追加される(またはプログラムが正常に終了する)まで、出力データをメモリーにバッファーし、その後、実際にwrite()を呼び出します。バッファの内容を書き込みます。後者の場合、メモリ内バッファーがいっぱいになる(またはプログラムが正常に終了する)だけがwrite()をトリガーします。

より詳細な説明

これはよく知られた説明ですが、少し間違っています。実際、標準出力は行バッファリングされていませんが、GNU CライブラリおよびBSD Cライブラリではsmart buffered)です。出力はまた、標準を読み取るときにフラッシュされますinput排気its(先読み入力の)メモリ内バッファとCライブラリはread()を呼び出して、さらに入力をフェッチする必要がありますand新しい行の先頭を読み取っています(これの1つの理由は、別のプログラムがフィルターの両端に接続し、操作できることを期待しているときにデッドロックを防ぐためです)フィルターへの書き込みとフィルターからの読み取りを交互に1行ずつ、たとえばGNU awkなどの "coprocesses")

Cライブラリの影響

grepおよび他のユーティリティがこれを行います。または、厳密には、使用するCライブラリがこれを行います。これは、Cでのプログラミングの定義済み機能であるため、標準出力が検出された内容に基づいているためです。 。インタラクティブデバイスではない場合に限り、フルバッファリングを選択します。それ以外の場合は、スマートバッファリングを選択します。少なくともUnixおよびLinuxの世界では、インタラクティブデバイスであることの定義は本質的にisatty()呼び出しであり、関連するファイル記述子に対してtrueを返すため、パイプはインタラクティブデバイスではないと見なされます。

完全なバッファリングを無効にする回避策

grepのような一部のユーティリティには、この決定を変更する--line-bufferedなどの特異なオプションがあります。しかし、実際に使用できるフィルタープログラムのごくわずかな部分に、このようなオプションがあります。

より一般的には、Cライブラリの特定の内部を掘り下げ、その意思決定を変更するツールを使用できます(変更されるプログラムがset-UIDである場合にセキュリティ上の問題があり、特定のCライブラリに固有であり、実際にC言語で記述された、またはC言語の上に階層化されたプログラムに固有)、またはptybandageなどのツールの内部を変更しないプログラムに影響を与えるために、決定は「対話型」として出てくるように、標準出力として疑似端末を単に挿入します。

参考文献

26
JdeBP

使用する

grep --line-buffered

grepが一度に複数の行をバッファリングしないようにします。

7
choroba