c-使用循环shell命令行调用popen()管道流



我正在测试这个使用管道编程的示例,它看起来非常简单。

但我想知道,如果第一个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");

最新更新