150

通常、stdoutは行バッファリングされます。つまり、引数が改行で終わっている限り、printfその行が即座に出力されることが期待できます。パイプを使用してにリダイレクトする場合、これは当てはまらないようteeです。

a常に\n終了する文字列をに出力するC++プログラムがありstdoutます。

単独で実行すると(./a)、すべてが正しく、適切なタイミングで期待どおりに印刷されます。teeただし、 ( )にパイプすると./a | tee output.txt、終了するまで何も出力されないため、を使用する目的が失われteeます。

fflush(stdout)C++プログラムで各印刷操作の後に追加することで修正できることを知っています。しかし、よりクリーンで簡単な方法はありますか?たとえば、stdoutパイプを使用している場合でも、強制的にラインバッファリングするコマンドを実行できますか?

4

6 に答える 6

153

あなたが試すことができますstdbuf

$ stdbuf --output=L ./a | tee output.txt

(大きい)マニュアルページの一部:

  -i, --input=MODE   adjust standard input stream buffering
  -o, --output=MODE  adjust standard output stream buffering
  -e, --error=MODE   adjust standard error stream buffering

If MODE is 'L' the corresponding stream will be line buffered.
This option is invalid with standard input.

If MODE is '0' the corresponding stream will be unbuffered.

Otherwise MODE is a number which may be followed by one of the following:
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.
In this case the corresponding stream will be fully buffered with the buffer
size set to MODE bytes.

ただし、これを覚えておいてください。

NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does
for e.g.) then that will override corresponding settings changed by 'stdbuf'.
Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O,
and are thus unaffected by 'stdbuf' settings.

で実行しているのではなく、で実行stdbufteeているので、ソースでストリームのaバッファリングを設定しない限り、これが影響することはありません。aa

また、 POSIXstdbufではなく、GNU-coreutilsの一部です。

于 2012-07-05T02:10:44.630 に答える
80

パッケージunbufferの一部であるものを試してください。expectあなたはすでにあなたのシステムにそれを持っているかもしれません。

あなたの場合、あなたはそれをこのように使うでしょう:

./a | unbuffer -p tee output.txt

-punbufferがstdinから読み取り、残りの引数でコマンドに渡すパイプラインモード用です)

于 2012-07-05T02:50:35.110 に答える
33

コマンドを使用して疑似端末でコマンドを実行することもできますscript(これにより、パイプへのラインバッファ出力が強制されます)。

script -q /dev/null ./a | tee output.txt     # Mac OS X, FreeBSD
script -c "./a" /dev/null | tee output.txt   # Linux

scriptコマンドは、ラップされたコマンドの終了ステータスを伝播しないことに注意してください。

于 2012-07-05T17:12:25.500 に答える
30

stdio.hからsetlinebufを使用できます。

setlinebuf(stdout);

これにより、バッファリングが「ラインバッファリング」に変更されます。

より柔軟性が必要な場合は、setvbufを使用できます。

于 2015-05-14T14:46:50.233 に答える
5

@Pausedのパッケージからのunbufferコマンドは、さらに通知の回答が表示されるまで機能しませんでした。expect

使用する代わりに:

./a | unbuffer -p tee output.txt

私は使用しなければなりませんでした:

unbuffer -p ./a | tee output.txt

-punbufferがstdinから読み取り、残りの引数でコマンドに渡すパイプラインモード用です)

パッケージは次のexpect場所にインストールできます。

  1. MSYS2とpacman -S expect
  2. MacOSとbrew install expect

アップデート

python最近、シェルスクリプト内でバッファリングの問題が発生しました(出力にタイムスタンプを追加しようとしたとき)。修正は、次の方法で-uフラグを渡すことでした。python

  1. run.shpython -u script.py
  2. unbuffer -p /bin/bash run.sh 2>&1 | tee /dev/tty | ts '[%Y-%m-%d %H:%M:%S]' >> somefile.txt
  3. このコマンドは、出力にタイムスタンプを付け、それをファイルとstdoutに同時に送信します。
  4. tsプログラム(タイムスタンプ)はパッケージと一緒にインストールできますmoreutils

アップデート2

最近、grep出力のバッファリングに問題がありました。引数を使用するとgrep --line-bufferedgrep出力のバッファリングが停止しました。

于 2020-08-15T12:11:33.750 に答える
2

代わりにC++ストリームクラスを使用する場合、すべてstd::endl 暗黙的なフラッシュです。fflush()Cスタイルの印刷を使用すると、あなたが提案した方法( )が唯一の方法だと思います。

于 2012-07-05T03:12:29.897 に答える