我想启动一个需要几分钟才能完成的程序。在此期间,我想阅读程序的进度消息(打印在标准输出上)。问题是我找不到在运行期间读出输出的方法。
我发现读取程序输出的唯一函数是Popen.communicate()
,但是这个方法一直等到进程完成。因此,无法获得进度并以特殊格式化方式使用户可见。
是否有可能以另一种方式做到这一点?
当我使用我的脚本subprocess.popen
运行该过程时,我会在屏幕上看到该程序的输出。有可能隐藏它吗? (Ubuntu 10.10,普通终端)
答案 0 :(得分:19)
最简单的方法是使用关键字参数stdout=subprocess.PIPE
调用Popen。
p = subprocess.Popen(["ls"], stdout=subprocess.PIPE)
while True:
line = p.stdout.readline()
if not line:
break
print line
要查看此操作,以下是两个示例脚本。将它们放在同一目录中并运行python superprint.py
printandwait.py:
import time
import sys
print 10
sys.stdout.flush()
time.sleep(10)
print 20
sys.stdout.flush()
superprint.py:
import subprocess
import sys
p = subprocess.Popen(["python printandwait.py"], shell=True, stdout=subprocess.PIPE)
while True:
print "Looping"
line = p.stdout.readline()
if not line:
break
print line.strip()
sys.stdout.flush()
答案 1 :(得分:2)
您可以对子流程的状态进行轮询并保持输出行。
p = subprocess.Popen('ls;sleep 10', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
rc = p.poll()
while rc != 0:
while True:
line = p.stdout.readline()
if not line:
break
print line
rc = p.poll()
assert rc == 0
答案 2 :(得分:1)
这当然是可能的:我的包python-gnupg
就是这样做的,在子流程下产生gpg
(Gnu Privacy Guard)。在一般情况下,您需要为子进程stdout和stderr指定subprocess.PIPE
;然后创建两个独立的线程,将子进程stdout和stderr读取到任何你喜欢的位置。
在python-gnupg
的情况下,来自gpg的状态消息在gpg
进程运行时被读取并执行(不等到它完成)。
基本上,伪代码是
process = subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr = process.stderr
rr = threading.Thread(target=response_reader_func, args=(process.stderr,))
rr.setDaemon(True)
rr.start()
dr = threading.Thread(target=data_reader_func, args=(process.stdout,))
dr.setDaemon(True)
dr.start()
dr.join()
rr.join()
process.wait()
读者功能通常是封闭类的方法,根据他们正在阅读的内容做正确的事情(在您的情况下,以某种方式更新进度信息)。