web-dev-qa-db-ja.com

stdoutをパイプで処理することはできません

私はFIFOでtsharkを実行していますが、以下はtsharkの出力を出力するループの裸の例です来たときに

tshark -i $fifo | while read line; do
    echo $line
done

Tsharkにフィルターを追加すると問題が発生します。この例では、tsharkが終了した後にのみすべての$lineを出力します(IPアドレスは非表示になっています)。

tshark -i $fifo -T fields -e text -R '
    ip.src == **.**.***.**          &&
    http.response.code == 200       &&
    http.content_encoding == "gzip" &&
    http.content_type contains "text/html"
' | while read line; do
    echo $line
done

私は運が悪かった他の形で試しました:

while read line; do
    echo $line
done < <(tshark ...)

while read line; do
    echo $line
done <<<"$(tshark ...)"

Grepでさえ、tsharkが終了した後にのみ行を出力します。

tshark ... | grep .

パイプなしでtsharkを実行してみましたが、線が正しく印刷されます。パイプがフィードされた後のコマンドが、tsharkが終了した後にのみ実行されるのはなぜですか?

追加の詳細:| teeは機能しますが、tsharkが終了するとすべてが再度印刷されるため、お得ではありません。

3
Teresa e Junior

tsharkバージョンには-l(ほぼ)ラインバッファ出力のオプション。

4
vro

Coreutilsのstdbufで動作させることができました。パイプの後のすべてのコマンドでは、バッファーも調整する必要があることに注意してください。

stdbuf -o 0 tshark -i $fifo -T fields -e text -R '
    ip.src == **.**.***.**          &&
    http.response.code == 200       &&
    http.content_encoding == "gzip" &&
    http.content_type contains "text/html"
' | 
stdbuf -o 0 sed 's/\\r\\n,\?/\n/g; s/\\t/\t/g' |

マニュアルページから:

`stdbuf': Run a command with modified I/O stream buffering

(...)

`-o MODE'
`--output=MODE'
     Adjust the standard output stream buffering.
4
Teresa e Junior

一部のユーティリティはisatty()を呼び出して、出力が端末であるかどうかを判断し、それに応じて動作を調整します。 gzipはこの良い例です。

script(1)で実行してみてください。

-c、-commandコマンド

対話型シェルではなくコマンドを実行します。これにより、スクリプトは、stdoutがttyでない場合に異なる動作をするプログラムの出力を簡単にキャプチャできます。

このように実行すると:

script -c tshark -i $fifo -T fields -e text -R '
    ip.src == **.**.***.**          &&
    http.response.code == 200       &&
    http.content_encoding == "gzip" &&
    http.content_type contains "text/html"
' | while read line; do
    echo $line
done

線がライブで出てくるのを見ることができるはずです。

3
Cera