python,subprocess:从子进程读取输出

时间:2010-09-27 14:21:22

标签: python subprocess stdout

我有以下脚本:

#!/usr/bin/python

while True:
    x = raw_input()
    print x[::-1]

我是从ipython调用它:

In [5]: p = Popen('./script.py', stdin=PIPE)

In [6]: p.stdin.write('abc\n')
cba

它工作正常。

然而,当我这样做时:

In [7]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)

In [8]: p.stdin.write('abc\n')

In [9]: p.stdout.read()
解释器挂起了。我究竟做错了什么?我希望能够多次写入和读取另一个进程,将一些任务传递给此进程。我需要做些什么不同的事情?

编辑1

如果我使用communicate,我明白了:

In [7]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)

In [8]: p.communicate('abc\n')
Traceback (most recent call last):
  File "./script.py", line 4, in <module>
    x = raw_input()
EOFError: EOF when reading a line
Out[8]: ('cba\n', None)

编辑2

我试着冲洗:

#!/usr/bin/python

import sys

while True:
        x = raw_input()
        print x[::-1]
        sys.stdout.flush()

在这里:

In [5]: from subprocess import PIPE, Popen

In [6]: p = Popen('./script.py', stdin=PIPE, stdout=PIPE)

In [7]: p.stdin.write('abc')

In [8]: p.stdin.flush()

In [9]: p.stdout.read()

但它又挂了。

6 个答案:

答案 0 :(得分:15)

我相信这里有两个问题:

1)您的父脚本调用p.stdout.read(),它将读取所有数据,直到文件结束。但是,您的子脚本在无限循环中运行,因此文件末尾永远不会发生。可能你想要p.stdout.readline()

2)在交互模式下,大多数程序一次只缓冲一行。从另一个程序运行时,它们可以缓冲更多。缓冲在许多情况下提高了效率,但是当两个程序需要交互式通信时会导致问题。

p.stdin.write('abc\n')之后添加:

p.stdin.flush()

在您的子流程脚本中,在print x[::-1]之后在循环中添加以下内容:

sys.stdout.flush()

(和import sys位于顶部)

答案 1 :(得分:3)

子流程方法check_output对此非常有用:

output = subprocess.check_output('./script.py')

输出将是该过程的标准输出。如果你也需要stderr:

output = subprocess.check_output('./script.py', stderr=subprocess.STDOUT)

由于您避免直接管理管道,因此可能会绕过您的问题。

答案 2 :(得分:3)

如果您想将多行传递给script.py,那么您需要同时读/写:

#!/usr/bin/env python
import sys
from subprocess import PIPE, Popen
from threading  import Thread

def print_output(out, ntrim=80):
    for line in out:
        print len(line)
        if len(line) > ntrim: # truncate long output
            line = line[:ntrim-2]+'..'
        print line.rstrip() 


if __name__=="__main__":
    p = Popen(['python', 'script.py'], stdin=PIPE, stdout=PIPE)
    Thread(target=print_output, args=(p.stdout,)).start()
    for s in ['abc', 'def', 'ab'*10**7, 'ghi']:
        print >>p.stdin, s
    p.stdin.close()
    sys.exit(p.wait()) #NOTE: read http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

输出:

4
cba
4
fed
20000001
bababababababababababababababababababababababababababababababababababababababa..
4
ihg

script.py

#!/usr/bin/env python
"""Print reverse lines."""
while True:
    try: x = raw_input()
    except EOFError:
        break # no more input
    else:
        print x[::-1]

或者

#!/usr/bin/env python
"""Print reverse lines."""
import sys

for line in sys.stdin:
    print line.rstrip()[::-1]

或者

#!/usr/bin/env python
"""Print reverse lines."""
import fileinput

for line in fileinput.input(): # accept files specified as command line arguments
    print line.rstrip()[::-1]

答案 3 :(得分:1)

你可能会绊倒Python的输出缓冲。以下是python --help对此的评论。

-u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x
         see man page for details on internal buffering relating to '-u'

答案 4 :(得分:1)

当你写到p.stdin时,请关闭它:p.stdin.close()

答案 5 :(得分:-3)

使用communicate()代替.stdout.read()

示例:

from subprocess import Popen, PIPE
p = Popen('./script.py', stdin=PIPE, stdout=PIPE, stderr=PIPE)
input = 'abc\n'
stdout, stderr = p.communicate(input)

此推荐来自Popen objects中的subprocess documentation部分:

  

警告:使用communic()而不是.stdin.write,.stdout.read或.stderr.read   避免由于任何其他OS管道缓冲区填满和阻塞导致的死锁   儿童过程。