有没有一种方法可以流式传输并捕获Python 3中subprocess.run的输出?

时间:2020-03-13 18:51:13

标签: python python-3.x subprocess

如果愿意

subprocess.run(["echo hi && sleep 60"], shell=True, capture_output=False, timeout=5)

您将在终端上看到“ hi”字样,然后由于超时而引发异常。

但如果您这样做

ret = subprocess.run(["echo hi && sleep 6"], capture_output=True, timeout=2, shell=True)

您将看不到任何输出,并且(据我所知)超时异常将阻止您获取生成的输出。 (shell=True对于本示例而言并不重要,我只需要一种方便的方法使其超时即可。)

这引起了以下问题:我(a)需要获取命令的输出,但(b)有时会无意中运行挂起的命令以等待用户输入。我真的很想能够捕获产生的任何输出,尽管抛出了超时异常,或者将输出流传输到stdout / stderr,同时还获得了它的副本。

1 个答案:

答案 0 :(得分:1)

TimeoutExpired exception本身包括任何捕获的输出作为属性(stdoutstderr),因此:

try:
    ret = subprocess.run("commands go here && sleep 6", capture_output=True, timeout=2, shell=True)
except subprocess.TimeoutExpired as e:
    print(e.stdout)
else:
    print(ret.stdout)

在有问题的命令在超时之前实际写入管道时将起作用。

但是,如果子进程在完成之前被杀死,而子进程仍然在用户模式缓冲区中保留数据(它是块缓冲或行缓冲,并且从来没有写过换行符之类的东西),那么它将永远不会被写入实际的管道,因此您将看不到它。

取消子进程的缓冲有许多不同的方式,因此我无法提供有关在实际情况下(echo显然只是一个占位符)的具体信息(stdbuf当无法修改子可执行文件以使其具有行缓冲或非缓冲状态时,通常很有用。