我正在测试这个使用管道编程的示例,它看起来非常简单。
但我想知道,如果第一个popen()调用(包含shell命令的字符串)的第一个参数包含"while do"循环,会发生什么。
例如,如果我执行这个shell命令3秒钟,我会得到以下输出:
tomas@ubuntu64:~$ while true; do ps -A; sleep 1; done | grep init
1 ? 00:00:03 init
1 ? 00:00:03 init
1 ? 00:00:03 init
因此grep在每次迭代中都在工作。
但是,如果我通过C语言示例来完成,则通过以下方式更改示例的popen():
FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "r");
在执行编译后的C程序时,我没有得到任何输出结果。
有人能对此有所了解吗?
Edit:正如J.F.Sebastian所注意到的,当输出不指向终端时,默认情况下grep使用大缓冲区。您需要使用选项--line-buffered
立即获得输出(每行之后)
嗯,我试过了,效果很好(感谢J.F.Sebastian的修复)。以下是FreeBSD 9盒子上的完整代码:
#include <stdio.h>
int main() {
char buffer[256];
FILE *fd = popen("while true; do ps -A; sleep 1; done | grep --line-buffered init", "r");
while(NULL != fgets(buffer, sizeof(buffer), fd)) {
printf("GOT >%s<n", buffer);
}
return 0;
}
并且(由于我没有删除buffer
末尾的n
),输出为:
GOT > 1 ?? ILs 0:00:02 /sbin/init --
>
GOT >1334 v0 R+ 0:00:00 grep --line-buffered init
>
GOT > 1 ?? ILs 0:00:02 /sbin/init --
>
GOT >1334 v0 R+ 0:00:00 grep --line-buffered init
>
这是一个块缓冲问题。当grep的stdout不是终端(tty)时,例如,当它是管道(由popen()
创建)时,就像您的情况一样;它使用块缓冲而不是行缓冲。在grep的stdout缓冲区溢出之前,您不会看到任何内容。将--line-buffered
参数添加到grep
中,您将立即(每秒)看到输出。
您所需要做的就是将输出write
转换为标准I/O,因此将popen()
参数更改为:
FILE* ps_pipe = popen("while true; do ps -A; sleep 1; done", "w");