如何读取另一个程序的输出?
我该如何在Python中从终端接收输入呢?
我正在用Python和另一个程序进行交互,这个程序根据用户输入生成输出。我使用subprocess.Popen()来向这个程序输入数据,但我无法把标准输出设置为subprocess.PIPE,因为这个程序似乎从来不刷新输出,所以所有的内容都卡在了缓冲区里。这个程序的标准输出似乎是直接打印到终端上,当我不重定向标准输出时,我能看到输出。不过,我需要Python来读取和理解现在在终端上的输出。
抱歉如果这个问题很傻,但我就是无法让它工作。
2 个回答
你有没有试过把你的 Popen
对象里的 bufsize
设置为 0
?我不太确定你能不能通过接收的大小来强制让缓冲区变成无缓冲的,但我建议你可以试试看。
http://docs.python.org/library/subprocess.html#using-the-subprocess-module
在子进程中缓冲是一个常见的问题。这里有四种可能的解决方法。
第一种,也是最简单的,你可以从管道中一次读取一个字节。这可以算是一种“临时解决办法”,虽然性能上会有一些损失,但操作简单,并且可以确保你的读取操作只会在第一个字节到达时阻塞,而不是等着一个永远不会填满的缓冲区。不过,这种方法并不能强制其他进程清空它的写缓冲区,所以如果问题出在这方面,这种方法也帮不了你。
第二种,我认为是下一个简单的选择,可以考虑使用Twisted框架,它有一个功能可以通过虚拟终端(pty,可能是“伪终端”的意思)与子进程进行通信。不过,这可能会影响你应用程序的设计(可能会变得更好,但这不一定适合你)。http://twistedmatrix.com/documents/current/core/howto/process.html
如果以上两种方法都不适合你,那你就得自己解决一些复杂的输入输出并发问题了。
第三种,尝试在fork()之前将所有管道设置为非阻塞模式,使用fcntl()和O_NONBLOCK。这样你可以在尝试读取或写入之前,使用select()来检查是否可以读取或写入;但你仍然需要捕获IOError并测试EAGAIN,因为即使在这种情况下也可能发生。这种方法可能会让你等到数据真的到达后再尝试读取。
最后的办法是自己实现PTY逻辑。如果你见过关于termio选项、ioctl()调用等的相关内容,那你就知道这会有多复杂。我之前没有做过这个,因为这很复杂,而且我也从来没有真正需要过。如果这就是你的命运,祝你好运。