简体   繁体   English

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

[英]Getting another program's output as input on the fly

I've two programs I'm using in this way: 我有两个以这种方式使用的程序:

$ c_program | python_program.py

c_program prints something using printf() and python_program.py reads using sys.stdin.readline() c_program使用printf()打印内容,使用sys.stdin.readline()读取sys.stdin.readline()

I'd like to make the python_program.py process c_program's output as it prints, immediately, so that it can print its own current output. 我想立即打印python_program.py进程c_program的输出,以便它可以打印自己的当前输出。 Unfortunately python_program.py gets its input only after c_program ends. 不幸的是,python_program.py仅在c_program结束后获取其输入。

How can I solve this? 我怎么解决这个问题?

Just set stdout to be line buffered at the beginning of your C program (before performing any output), like this: 只需将stdout设置为在C程序开始时进行行缓冲(在执行任何输出之前),如下所示:

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

or 要么

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

Either one will work on Linux, but setvbuf is part of the C standard so it will work on more systems. 任何一个都可以在Linux上运行,但是setvbuf是C标准的一部分,因此它可以在更多系统上运行。

By default stdout will be block buffered for a pipe or file, or line buffered for a terminal. 默认情况下,stdout将为管道或文件进行块缓冲,或者为终端缓冲行。 Since stdout is a pipe in this case, the default will be block buffered. 由于在这种情况下stdout是管道,因此默认将是块缓冲。 If it is block buffered then the buffer will be flushed when it is full, or when you call fflush(stdout) . 如果它是块缓冲的,那么当缓冲区已满或者调用fflush(stdout)时将刷新缓冲区。 If it is line buffered then it will be flushed automatically after each line. 如果它是行缓冲的,那么它将在每行之后自动刷新。

What you need is for your C program to call fflush(stdout) after every line. 你需要的是你的C程序在每一行之后调用fflush(stdout)。 For example, with the GNU grep tool, you can invoke the option '--line-buffered', which causes this behavior. 例如,使用GNU grep工具,您可以调用选项'--line-buffered',这会导致此行为。 See fflush . fflush

If you can modify your C program, you've already received your answer but i thought i'd include a solution for those that can't/won't modify code. 如果你可以修改你的C程序,你已经收到了你的答案,但我想我会为那些不能/不会修改代码的人提供一个解决方案。

expect has an example script called unbuffer that will do the trick. expect有一个名为unbuffer的示例脚本可以解决问题。

All the Unix shells (that I know of) implement shell pipelines via something else than a pty (typically, they use Unix pipes!-); 所有Unix shell(我所知道的)都是通过pty之外的东西实现shell管道(通常,它们使用Unix管道! - ); therefore, the C/C++ runtime library in cpp_program will KNOW its output is NOT a terminal, and therefore it WILL buffer the output (in chunks of a few KB at a time). 因此, cpp_program的C / C ++运行时库将知道它的输出不是终端,因此它将缓冲输出(一次以几KB的块为单位)。 Unless you write your own shell (or semiquasimaybeshelloid) that implements pipelines via pyt's, I believe there is no way to do what you require using pipeline notation. 除非你编写自己的shell(或semiquasimaybeshelloid)通过pyt实现管道,我相信没有办法用管道符号来做你需要的。

The "shelloid" thing in question might be written in Python (or in C, or Tcl, or...), using the pty module of the standard library or higher-level abstraction based on it such as pexpect , and the fact that the two programs to be connected via a "pty-based pipeline" are written in C++ and Python is pretty irrelevant. 有问题的“shelloid”事物可能是用Python(或C,或Tcl,或......)编写的,使用标准库的pty模块或基于它的更高级抽象,例如pexpect ,以及通过“基于pty的管道”连接的两个程序是用C ++编写的,Python是无关紧要的。 The key idea is to trick the program to the left of the pipe into believing its stdout is a terminal (that's why a pty must be at the root of the trick) to fool its runtime library into NOT buffering output. 关键的想法是欺骗管道左边的程序,让它相信它的stdout是一个终端(这就是为什么pty必须在技巧的根源)来欺骗它的运行时库到NOT缓冲输出。 Once you have written such a shelloid, you'd call it with some syntax such as: 一旦你编写了这样的shelloid,你就会用一些语法来调用它,例如:

$ shelloid 'cpp_program | $ shelloid'cpp_program | python_program.py' python_program.py”

Of course it would be easier to provide a "point solution" by writing python_program in the knowledge that it must spawn cpp_program as a sub-process AND trick it into believing its stdout is a terminal (ie, python_program would then directly use pexpect , for example). 当然,通过编写python_program提供一个“点解决方案”会更容易,因为它必须将cpp_program作为一个子进程生成,并且让它相信它的stdout是一个终端(即python_program会直接使用pexpect ,因为例)。 But if you have a million of such situations where you want to defeat the normal buffering performed by the system-provided C runtime library, or many cases in which you want to reuse existing filters, etc, writing shelloid might actually be preferable. 但是如果你有数百万这样的情况想要打败由系统提供的C运行时库执行的正常缓冲,或者你想要重用现有过滤器等的许多情况,那么编写shelloid可能实际上更可取。

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

ok this maybe sound stupid but it might work: 好吧这可能听起来很愚蠢,但它可能会起作用:

output your pgm to a file 将您的pgm输出到文件

$ c_program >> ./out.log

develop a python program that read from tail command 开发一个从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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM