如何使用子进程和Popen从长时间运行的进程返回stdout?

时间:2014-03-08 00:28:13

标签: python shell subprocess stdout

我正在使用subprocess.Popen()的一个非常基本的设置,并将stdout指向一个变量,我后来将其返回到我的python脚本的不同部分。

这是我的基本Popen代码:

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# wait for the process to terminate
out, err = process.communicate()
errcode = process.returncode
print out

这适用于许多基本用例,例如ls -al或类似用途。但是,我想知道如何从更长(或无限期)运行的进程(例如tail -f foo.log)定期和一致地处理输出。有没有办法在循环中定期读取stdout?或者产生一个线程来检查并定期返回每个线程?这里最好的方法是什么?

谢谢!

1 个答案:

答案 0 :(得分:5)

我认为重要的是要注意原始代码不正确(或者说,不安全)。 它通常会起作用,但是在给定的示例中没有任何内容等待进程退出。它可能仍在运行。

process.poll()process.wait()是实现此目的的两个不错的选择。


当你不知道输出有多大时,communicate是危险的,因为它会将输出缓冲到内存中,并可能使你无法运行。但是,如果您使用的是subprocess.PIPE,则无论如何都可能会发生这种情况。

您应该根据自己的需要谨慎选择stdoutstderr的目标。如果它可能非常大,写入磁盘上的文件可能是最好的选择。然而,这是一个单独的讨论。


要查看输出而不等待关闭进程,你应该在一个单独的线程中运行这样的东西:

while process.returncode is None:
    # handle output by direct access to stdout and stderr
    for line in process.stdout:
        print line
    # set returncode if the process has exited
    process.poll()

我愿意接受有关如何实际访问文件对象stdoutstderr的评论,但这是随便想到的。

虽然这是处理衍生子进程的最强大方法,但如果可以的话,请认真考虑使用process.wait() - 它只会使一切变得更加简单。