现在我有一些代码使用来自子进程的Popen.communicate()
(设置stdin=PIPE
和stderr=PIPE
)来运行命令并捕获stderr和stdout。
问题是communicate()
不仅等待命令退出,还等待stdout和stderr关闭。我正在运行的命令会产生一个子进程,它会使stderr保持打开状态,所以即使命令运行完毕(并在ps中显示为“defunct”),communicate()
仍然挂起。
我想只等待命令完成而不等待stderr / stdout。但我仍然希望捕获命令运行时给出的任何stderr / stdout输出。 The documentation for wait()
附有一个带有免责声明的红色框:
当使用stdout = PIPE和/或stderr = PIPE并且子进程为管道生成足够的输出以阻止等待OS管道缓冲区接受更多数据时,这将会死锁。使用communic()来避免这种情况。
显然,我也想避免陷入僵局。
完成此任务的正确方法是什么?
答案 0 :(得分:1)
“在ps中显示为”defunct“”意味着你可能在select
或fcntl
工作的系统上,即你可以在没有stdout / stderr的情况下阅读很容易阻挡。
示例:A启动B(cmd
,孩子),B启动C(孙子),A读取输出直到B退出或EOF:
#!/usr/bin/env python
import os
from select import select
from subprocess import Popen, PIPE
p = Popen(cmd, stdout=PIPE, stderr=PIPE, bufsize=0)
read_set = [p.stdout, p.stderr]
pipename = {p.stdout: "stdout", p.stderr: "stderr"}
timeout = 0.5 # ugly but it works
while read_set and p.poll() is None: # while subprocess is running or until EOF
for pipe in select(read_set, [], [], timeout)[0]:
data = os.read(pipe.fileno(), 1<<30)
if data:
print("got from %s: %r" % (pipename[pipe], data))
else: # EOF
pipe.close()
read_set.remove(pipe)
print("exit code %s" % (p.wait(),))
# child exited, wait for grandchild to print
for pipe in read_set:
print("read the rest of %s: %r" % (pipename[pipe], pipe.read()))
pipe.close()
其中cmd
:
import sys
from textwrap import dedent
cmd = [sys.executable, '-u', '-c', dedent("""
# inception style
import os
import sys
from subprocess import Popen
from textwrap import dedent
Popen([sys.executable, '-u', '-c', dedent('''
import os
import sys
import time
time.sleep(60)
print("grandchild %d done" % os.getpid())
sys.stderr.write("grandchild stderr")
sys.exit(20)
''')]) # stdout/stderr are not redirected
print('child %d done' % os.getpid())
sys.stderr.write('child stderr')
sys.exit(19)
""")]
答案 1 :(得分:0)
我尝试过一个简单的例子。到目前为止我所拥有的只是捕获std.err我创建了两个文件。第一个的内容是(example1.py):
import time
import sys
for i in xrange(1000):
print >>sys.stderr, "hello", i
time.sleep(1)
第二个内容(example2.py):
import subprocess
cmd = "python example1.py"
print subprocess.check_output(cmd, shell=True)
我刚刚调用了example2.py脚本:
python example2.py 我有实时输出(我认为这是真的:)):
hello 0
hello 1
hello 2
hello 3
hello 4
hello 5
hello 6
不过,我不知道如何处理标准输出,但如果我管理它,我会在这里发布答案