动态获取另一个程序的输出作为输入

时间:2009-09-11 02:12:28

标签: python c linux bash stdio

我正以这种方式使用两个程序:

$ c_program | python_program.py

c_program使用printf()打印内容并使用sys.stdin.readline()读取python_program.py

我想立即打印python_program.py进程c_program的输出,以便它可以打印自己的当前输出。不幸的是,python_program.py仅在c_program结束后获取其输入。

我该如何解决这个问题?

6 个答案:

答案 0 :(得分:17)

只需将stdout设置为在C程序开始时进行行缓冲(在执行任何输出之前),如下所示:

#include <stdio.h>
setvbuf(stdout, NULL, _IOLBF, 0);

#include <stdio.h>
setlinebuf(stdout);

任何一个都可以在Linux上运行,但setvbuf是C标准的一部分,因此它可以在更多系统上运行。

默认情况下,stdout将为管道或文件进行块缓冲,或者为终端缓冲行。由于在这种情况下stdout是管道,因此默认将是块缓冲。如果它是块缓冲的,那么当缓冲区已满或者调用fflush(stdout)时将刷新缓冲区。如果它是行缓冲的,那么它将在每行之后自动刷新。

答案 1 :(得分:8)

你需要的是你的C程序在每一行之后调用fflush(stdout)。例如,使用GNU grep工具,您可以调用选项'--line-buffered',这会导致此行为。请参阅 fflush

答案 2 :(得分:7)

如果你可以修改你的C程序,你已经收到了answer,但我想我会为那些不能/不会修改代码的人提供一个解决方案。

expect有一个名为unbuffer的示例脚本可以解决问题。

答案 3 :(得分:1)

所有Unix shell(我所知道的)都是通过pty以外的东西实现shell管道 (通常,他们使用Unix管道! - );因此,cpp_program中的C / C ++运行时库将知道它的输出不是终端,因此它将缓冲输出(一次以几KB的块为单位)。除非你编写自己的shell(或semiquasimaybeshelloid)通过pyt实现管道,我相信没有办法用管道符号来做你需要的。

有问题的“shelloid”可能是用Python(或C,或Tcl,或......)编写的,使用标准库的pty模块或基于它的更高级抽象。作为pexpect,并且通过“基于pty的管道”连接的两个程序是用C ++和Python编写的,这一点非常无关紧要。关键的想法是欺骗管道左边的程序,让它相信它的stdout是一个终端(这就是为什么pty必须在技巧的根源)来欺骗它的运行时库到NOT缓冲输出。一旦你编写了这样的shelloid,你就会用一些语法来调用它,例如:

$ shelloid'cpp_program | python_program.py'

当然,通过编写python_program知道必须将cpp_program作为子进程生成并提示它相信其stdout是终端,这将更容易提供“点解决方案” (例如,python_program将直接使用pexpect,例如)。但是,如果您有数百万这样的情况,您希望打败由系统提供的C运行时库执行的正常缓冲,或者您希望重用现有过滤器等的许多情况,那么写shelloid实际上可能是优选的。

答案 4 :(得分:1)

您可能想在cpp程序中尝试flush stdout流。

答案 5 :(得分:-1)

好吧,这可能听起来很愚蠢,但可能会有效:

将您的pgm输出到文件

$ c_program >> ./out.log

开发一个从tail命令

读取的python程序
import os

tailoutput = os.popen("tail -n 0 -f ./out.log")

try:
    while 1:
        line = tailoutput.readline()
        if len(line) == 0:
            break

        #do the rest of your things here
        print line

except KeyboardInterrupt:
        print "Quitting \n"