T型への配管時にstdoutのラインバッファリングを強制する


116

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

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

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

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

回答:


66

パッケージのunbuffer一部であるものを試してくださいexpect。システムにすでにある可能性があります。

あなたの場合は次のように使用します:

./a | unbuffer -p tee output.txt

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


私がコンパイルしなければならなかったもののおかげで、これは、働いていたexpectとして自分自身をunbufferOS Xにデフォルトで含まれていないようだ
houbysoft

@houbysoft:うまくいったことを嬉しく思います。unbufferは小さなスクリプトなので、パッケージ全体を再コンパイルする必要はありませんでした。
追って通知があるまで一時停止。

ええ、おそらくそうではありませんが、./configure && make約10秒かかってから、私は:)に移動unbufferしました/usr/local/bin
houbysoft

3
私はそれをbrew経由で私のMac(10.8.5)にインストールしました:brew install expect --with-
Nils

2
FWIW、unbufferはやや混乱するため、関連する構造はunbuffer {commands with pipes/tee}です。
偽名

127

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

$ stdbuf -o 0 ./a | tee output.txt

manページの(大きな)部分:

  -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ので、のソースaでのストリームのバッファリングを設定しない限り、これが影響することはありませんa

また、stdbufあるではない POSIXが、GNU coreutilsの-の一部。


3
おかげで、これはOS Xでは利用できないようです(質問にはosx-lionのタグが付けられています)。
houbysoft 2012

2
@houbysoft-OS XにGNUツールをインストールできると確信しています
jordanm

1
@jordanm:たぶん、しかし、GNUツール全体をインストールすることは、これではやりすぎのように思えます...
houbysoft

1
stdbuf私たちが使用しているCentos Linuxディストリビューションではすでに利用可能であり、利用できないため、この回答に賛成しましたunbuffer。ありがとう!
Huw Walters

6
Pythonスクリプトのstdbufのために動作しませんが、あなたは使用することができます-uPythonの側で無効にバッファリング:python3 -u a.py | tee output.txt
Honza

27

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

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

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


3
script -t 1 /path/to/outputfile.txt ./a私のユースケースに最適です。すべての出力をライブストリームoutputfile.txtし、シェルの標準出力に出力します。使用する必要はありませんでしたtee
Peter Berg

26

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

setlinebuf(stdout);

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

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


8
なぜこのソリューションは賛成票が非常に少ないのでしょうか。これは、発信者に負担をかけない唯一の解決策です。
酸素供給

1
これは標準のC(またはPOSIX)ではないことに注意してください。setvbuf(stdout, NULL, _IOLBF, 0)まったく同じであるを使用する方がおそらく良いでしょう。
rvighne

これにより、OS Xカタリナでprintf()を実行しているC ++プログラムを使用して問題が修正され、T字型にパイピングしていましたが、プログラムが終了したときにのみ出力が表示されました。
jbaxter

2

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


4
残念ながら、これは正しくありません。std :: endlまたはstd :: flushを使用している場合でも、c ++ std :: coutで同じ動作を確認できます。バッファリングは上で行われ、Linuxでの最も簡単な解決策はsetlinebuf(stdout)のようです。プログラムの作成者がmain()の最初の行として、ソースコードを変更できないときに上記の他のソリューションを使用する場合。
酸素

1
@oxygeneこれは真実ではありません。私はそれを試しました、そして、endlはティーにパイプするとき(printfとは異なり)バッファをフラッシュします。コード:#include <iostream> #include <unistd.h> int main(void) { std::cout << "1" << std::endl; sleep(1); std::cout << "2" << std::endl; }。ここで定義されているようENDL常にバッファをフラッシュ:en.cppreference.com/w/cpp/io/manip/endl
カーティスYallop
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.