如何从 subprocess.Popen() 获取输出。 proc.stdout.readline() 块,没有数据打印出来
Posted
技术标签:
【中文标题】如何从 subprocess.Popen() 获取输出。 proc.stdout.readline() 块,没有数据打印出来【英文标题】:How to get output from subprocess.Popen(). proc.stdout.readline() blocks, no data prints out 【发布时间】:2010-11-26 04:50:48 【问题描述】:我想要执行 Test_Pipe.py 的输出,我在 Linux 上尝试了以下代码,但没有成功。
Test_Pipe.py
import time
while True :
print "Someting ..."
time.sleep(.1)
Caller.py
import subprocess as subp
import time
proc = subp.Popen(["python", "Test_Pipe.py"], stdout=subp.PIPE, stdin=subp.PIPE)
while True :
data = proc.stdout.readline() #block / wait
print data
time.sleep(.1)
proc.stdout.readline()
行被阻塞,所以没有数据打印出来。
【问题讨论】:
重复:***.com/search?q=%5Bpython%5D+subprocess+output、***.com/questions/803265/…、***.com/questions/1277866/… 【参考方案1】:您显然可以使用 subprocess.communicate 但我认为您正在寻找实时输入和输出。
readline 被阻止,因为该进程可能正在等待您的输入。您可以逐个字符地阅读来克服这个问题,如下所示:
import subprocess
import sys
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
while True:
out = process.stdout.read(1)
if out == '' and process.poll() != None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
【讨论】:
you don't needprocess.poll()
in this case.【参考方案2】:
Nadia 的 sn-p 确实有效,但非常不推荐使用 1 字节缓冲区调用 read。更好的方法是使用 fcntl 将 stdout 文件描述符设置为非阻塞
fcntl.fcntl(
proc.stdout.fileno(),
fcntl.F_SETFL,
fcntl.fcntl(proc.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
)
然后使用select来测试数据是否准备好
while proc.poll() == None:
readx = select.select([proc.stdout.fileno()], [], [])[0]
if readx:
chunk = proc.stdout.read()
print chunk
她是正确的,因为您的问题必须与您发布的 Caller.py 和 Test_Pipe.py 所提供的不同。
https://derrickpetzold.com/p/capturing-output-from-ffmpeg-python/【讨论】:
由于the block-buffering issue. See my answer,它不会比问题中的代码更快地产生输出。 代码确实会产生实时输出。你有问题吗? 点击评论中的链接。 数据“准备就绪”是什么意思?是换行还是至少一个字节的数据准备好了(即使此类数据的生产者仍在写入其标准输出)? @me,J.F.Sebastian 下面的回答解决了这个问题。【参考方案3】:Test_Pipe.py
默认缓冲其标准输出,因此 Caller.py
中的 proc
在子缓冲区已满之前看不到任何输出(如果缓冲区大小为 8KB,则填充 Test_Pipe.py
大约需要一分钟' s 标准输出缓冲区)。
要使输出无缓冲(文本流的行缓冲),您可以将 -u
flag 传递给子 Python 脚本。它允许“实时”逐行读取子进程的输出:
import sys
from subprocess import Popen, PIPE
proc = Popen([sys.executable, "-u", "Test_Pipe.py"], stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
print line,
proc.communicate()
请参阅Python: read streaming input from subprocess.communicate() 中的链接,了解如何解决非 Python 子进程的块缓冲问题。
【讨论】:
再次使用 1 字节缓冲区,这非常低效。 @DerrickPetzold:错了。bufsize=1
表示“行缓冲”。它使用与bufsize=-1
相同的缓冲区大小。如果您实际运行代码,您可能会发现您的两个 cmets 都是错误的(比较时间性能并测量读取第一个字节之前的时间)
我喜欢这种方式,因为您可以直接打印到屏幕上,还可以存储 popen 的结果以做某事,然后检查错误代码等...竖起大拇指 =) 我在没有 bufsize 的情况下运行它,并且在我的代码中对我来说工作正常。【参考方案4】:
为了避免诸如“实时获取子进程的输出到主进程”之类的任务缓冲经常出现的许多问题,我始终建议对所有非 Windows 平台使用pexpect,wexpect on Windows,而不是 subprocess
,当需要此类任务时。
【讨论】:
以上是关于如何从 subprocess.Popen() 获取输出。 proc.stdout.readline() 块,没有数据打印出来的主要内容,如果未能解决你的问题,请参考以下文章
如何从 subprocess.Popen 使用 STDIN [重复]
Python:使用 subprocess.call 获取输出,而不是 Popen [重复]
将标准输出从 subprocess.Popen 保存到文件,并将更多内容写入文件