Python在子进程终止后捕获输出

7

我正在尝试在Windows上获取子进程输出,在TimeoutExpired异常被触发的同时。有什么想法吗?

try:
    proc = subprocess.run(cmd,timeout=3)
except subprocess.TimeoutExpired:
    print(???)

自Python 3.5以来,TimeoutExpired异常似乎拥有stdoutstderr属性,用于该目的(假设您在调用run时设置了capture_output=True)。然而,目前它对我似乎不起作用。 - ingomueller.net
3个回答

10

当超时到期时,您需要使用Popensubprocess.PIPE来捕获进程输出。特别地,Popen.communicate是您所需的。

这里是一个例子
proc = subprocess.Popen(["ping", "192.168.1.1"],
                        stdout=subprocess.PIPE)

try:
    output, error = proc.communicate(timeout=2)
except subprocess.TimeoutExpired:
    proc.kill()
    output, error = proc.communicate()
    print(output)
    print(error)

这将打印进程输出直到超时过期。

谢谢你的回答,@Leonardo。我尝试了一下,但它只打印出命令,而不是进程的输出:"Command '[..., ...]' timed out after 4 seconds"(就像你示例中的第二个输出行一样)。我想在进程终止时打印子进程的输出。 - Ali_G
@Ali_G,我已经找到了解决方案,请告诉我。 - lch
对我也不起作用...我认为问题就像@J.F.Sebastian在其他帖子中提到的那样(即[链接](https://dev59.com/BFsX5IYBdhLWcg3wY-rX#33886970))。 无论如何,谢谢! - Ali_G

2
如果由于某种原因无法使用 timeout (其中之一是Python版本过旧),这里是我的解决方案,可以在任何Python版本上运行:

  • 创建一个线程,首先等待然后杀死 subprocess 对象
  • 在主线程中,使用循环读取行。

我正在使用Python子进程,并使用 -u (无缓冲)选项运行:

transmitter.py:(测试程序每1/10秒打印“hello xx”)

import time

i=0
while True:
    print("hello {}".format(i))
    i += 1
    time.sleep(0.1)

程序本身(超时设置为1.5秒):
import subprocess,threading,time

def timeout(p,timeout):
    time.sleep(timeout)
    p.kill()

p = subprocess.Popen(["python","-u","transmitter.py"],stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
t = threading.Thread(target=timeout,args=(p,1.5))
t.start()
output = []
for line in p.stdout:
    output.append(line.decode())

t.join()
print("".join(output))

最终,在超时后,程序将打印出以下内容:
hello 0
hello 1
hello 2
hello 3
hello 4
hello 5
hello 6
hello 7
hello 8
hello 9
hello 10
hello 11
hello 12
hello 13
hello 14

0

这里是捕获 multiprocessing.Process 的标准输出的方法

import app
import sys
import io
from multiprocessing import Process


def run_app(some_param):
    sys.stdout = io.TextIOWrapper(open(sys.stdout.fileno(), 'wb', 0), write_through=True)
    app.run()

app_process = Process(target=run_app, args=('some_param',))
app_process.start()
# Use app_process.termninate() for python <= 3.7.
app_process.kill() 

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