读取刷新的vs未刷新的缓冲区

时间:2012-09-28 02:23:47

标签: python c shell ipc

我有一个脚本parent.py试图从Python中的子进程sub.py读取stdout。

parent.py

#!/usr/bin/python
import subprocess
p = subprocess.Popen("sub.py", stdout=subprocess.PIPE)
print p.stdout.read(1)

子流程sub.py

#!/usr/bin/python
print raw_input( "hello world!" )

我希望运行parent.py来打印“hello world!”中的'h'。实际上,它挂了。我只能通过将-u添加到sub.py的she-bang行来获得我预期的行为。

这让我感到困惑,因为当-u直接从shell运行时,sub.py开关没有任何区别;与parent.py不同,shell在某种程度上与未刷新的输出流有关。

我的目标是运行一个C程序作为子进程,所以我无法控制它是否刷新stdout。如果从subprocess.Popen运行相同的东西,shell对进程的stdout有更好的访问权限,那该怎么办?我是否能够从不刷新缓冲区的C程序中读取这样的stdout流?

修改

以下是基于korylprince评论的更新示例......

## capitalize.sh ##
#!/bin/sh

while [ 1 ]; do
    read s
    echo $s | tr '[:lower:]' '[:upper:]'
done

########################################

## parent.py ##
#!/usr/bin/python 
from subprocess import Popen, PIPE

# cmd = [ 'capitalize.sh' ] # This would work
cmd = [ 'script', '-q', '-f', '-c', 'capitalize.sh', '/dev/null']

p = Popen(cmd, stdin=PIPE)
p.stdin.write("some string\n")
p.wait()

当通过script运行时,我会稳定地打印换行符(如果这是一个Python,则子进程,它会引发一个EOFerror)。

2 个答案:

答案 0 :(得分:1)

另一种选择是

p = subprocess.Popen(["python", "-u", "sub.py"], stdout=subprocess.PIPE)

或建议here

我的经验是,是的,您将能够从大多数C程序中读取而无需任何额外的努力。

Python解释器采取额外的步骤来缓冲其输出,这就是为什么它需要-u开关来禁用输出缓冲。你典型的C程序不会这样做。

除了我希望工作的Python解释器之外,我没有遇到任何程序(C或其他),并且不在子shell中。

答案 1 :(得分:0)

无论“-u”如何,shell都可以立即读取输出的原因是因为从shell启动的程序将其输出连接到TTY。当stdout连接到TTY时,它是无缓冲的(因为它取决于要缓冲的TTY)。当您从python中启动python子进程时,您将stdout连接到管道,这意味着您可以在子进程的情况下在其感觉时刷新其输出。

如果您希望与子流程进行复杂的交互,请查看this tutorial.