从子进程获取进度消息

时间:2011-02-09 22:07:07

标签: python subprocess

我想启动一个需要几分钟才能完成的程序。在此期间,我想阅读程序的进度消息(打印在标准输出上)。问题是我找不到在运行期间读出输出的方法。

我发现读取程序输出的唯一函数是Popen.communicate(),但是这个方法一直等到进程完成。因此,无法获得进度并以特殊格式化方式使用户可见。

是否有可能以另一种方式做到这一点?

当我使用我的脚本subprocess.popen运行该过程时,我会在屏幕上看到该程序的输出。有可能隐藏它吗? (Ubuntu 10.10,普通终端)

3 个答案:

答案 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()

读者功能通常是封闭类的方法,根据他们正在阅读的内容做正确的事情(在您的情况下,以某种方式更新进度信息)。