2012-07-05 31 views
63

通常,stdout是行缓冲。换句话说,只要您的printf参数以换行符结束,您可以期望该行即刻打印。当使用管道重定向到tee时,这似乎不成立。力线缓冲时发球

我有一个C++程序,a,输出字符串,总是\n - 终止,到stdout

当它本身(./a)运行,一切正常打印,并在合适的时机,符合市场预期。但是,如果我将其输入到tee./a | tee output.txt),它将不会打印任何内容,直到它退出为止,这会破坏使用tee的目的。

我知道我可以通过在C++程序每一次印制操作之后加入fflush(stdout)修复它。但是,有没有更简单,更简单的方法?有没有我可以运行的命令,例如,即使在使用管道时也会强制stdout进行行缓冲?

回答

26

尝试unbuffer其为expect包的一部分。您可能已经在您的系统上安装了它。

+0

谢谢,这工作,虽然我不得不编译'希望'我自己作为'unbuffer'似乎没有被默认包含在OS X中。 – houbysoft

+0

@houbysoft:我很高兴它为你工作。 'unbuffer'只是一个小脚本,所以你不需要重新编译整个软件包。 –

+0

是的,可能不是,'./configure && make'花了大约10秒,然后我把'unbuffer'移动到了'/ usr/local/bin' :) – houbysoft

81

你可以尝试stdbuf

$ stdbuf -o 0 ./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,所以这不应该影响你,除非你在a的源文件中设置缓冲a的流。

另外,stdbuf不是 POSIX,但是GNU-coreutils的一部分。

+2

谢谢,但这似乎没有在OS X上可用(问题被标记为osx-lion)。 – houbysoft

+1

@houbysoft - 我很确定GNU工具可以安装在OS X – jordanm

+1

@jordanm:也许,但安装整个GNU工具似乎对这个过度... – houbysoft

1

如果使用C++流类替代,每个std::endl隐式刷新。使用C式打印,我认为你建议的方法(fflush())是唯一的方法。

+2

不幸的是,这是不正确的。即使使用std :: endl或std :: flush,你也可以用C++ std :: cout观察同样的行为。缓冲发生在Linux上,Linux中最简单的解决方案似乎是setlinebuf(stdout)。作为main()中的第一行,当你是程序的作者时,在不能更改源代码时使用其他上述解决方案。 – oxygene

+0

@oxygene这是不正确的。我尝试过,endl在管道连接到tee时冲洗缓冲区(与printf不同)。代码:'#include #include int main(void){std :: cout <<“1”<< std :: endl;睡眠(1); std :: cout <<“2”<< std :: endl; }'。 endl总是按照以下定义刷新缓冲区:http://en.cppreference.com/w/cpp/io/manip/endl –

23

您也可以尝试在执行你的命令伪终端使用script命令(应执行行缓冲输出管道)!

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

请注意script命令不传播包装命令的退出状态。

+2

'script -t 1 /path/to/outputfile.txt。/ a'对我的工作很好用例。它直播所有输出到'outputfile.txt',同时也打印到你的shell的标准输出。不需要使用'tee' –

12

您可以使用stdio.h中的setlinebuf。

setlinebuf(stdout); 

这应该将缓冲更改为“行缓冲”。

如果您需要更多的灵活性,你可以使用调用setvbuf。

+2

我想知道为什么这个解决方案有这么几个upvotes。这是不会给呼叫者带来负担的唯一解决方案。 – oxygene