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

13 投票
6 回答
29190 浏览
提问于 2025-04-16 04:38

我有以下这个脚本:

#!/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 个回答

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

subprocess模块中的方法 check_output 对这个问题很有帮助:

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

这里的output就是运行这个脚本时的标准输出内容。如果你还需要错误输出的话:

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

因为你不需要直接处理管道,这样可能就能解决你的问题。

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

撰写回答