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

7

我将使用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?或生成一个线程来定期检查和返回每个结果?这里最好的方法是什么?
谢谢!

请根据需要使用“轮询”、“stdout.read()”和“returncode”等方法,参见手册,而不是“通信”。 - isedev
你可以使用逐行读取子进程的标准输出来读取单个流。如果要分别读取两个流而不阻塞,可以参考Python中subprocess.PIPE的非阻塞读取(有使用线程、fcntl、select、iocp等解决方案)。 - jfs
1个回答

9
我认为需要注意的是原始代码不正确(或者说是不安全的)。通常它可以工作,但在给定的示例中,没有任何东西等待进程退出。可能进程仍然在运行。 process.poll() 和 process.wait() 是这个目的的两个好选择。
当您不知道输出可能有多大时,communicate 是危险的,因为它会将输出缓冲到内存中,可能会耗尽内存。但是,如果您使用 subprocess.PIPE,则可能会发生这种情况。
根据您的需求,您应该仔细选择 stdout 和 stderr 的目标。如果可能非常大,将其写入磁盘上的文件可能是最佳选择。然而,那是一个单独的讨论。
要查看输出而不等待进程关闭,您应该在单独的线程中运行类似于此的内容:
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() -- 这会使一切变得更加简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接