用Python处理子进程通过stderr和stdout发送的消息

6 投票
2 回答
2456 浏览
提问于 2025-04-16 10:39

我的Python代码会创建一个子进程,并且它会同时在标准输出(stdout)和标准错误(stderr)中打印消息。我需要把这两种输出区分开来。

我有以下代码来创建子进程,并获取它的标准输出结果。

cmd = ["vsmake.exe", "-f"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
    print line,
    sys.stdout.flush()
    pass
p.wait()

我该如何修改这段代码,以便检查子进程是否也通过标准错误输出消息呢?

补充说明

我需要在子进程打印出内容的同时,立刻打印出标准错误和标准输出。而且这个实现需要跨平台,所以它应该能在Mac、Linux和PC上运行。

2 个回答

1

最简单的跨平台实现方式是使用线程(虽然这有点遗憾)。下面是一些示例代码:

def redirect_to_stdout(stream):
    for line in stream:
        sys.stdout.write(line)
        sys.stdout.flush()

cmd = ["vsmake.exe", "-f"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr_thread = threading.Thread(target=redirect_to_stdout, args=(p.stderr,))
stderr_thread.start()
redirect_to_stdout(p.stdout)
p.wait()
stderr_thread.join()
7
p = Popen(cmd, bufsize=1024,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
p.stdin.close()
print p.stdout.read() #This will print the standard output from the spawned process
print p.stderr.read() #This is what you need, error output <-----

简单来说,错误信息会被重定向到 stderr 管道。

如果你想要更实时的反馈,也就是说,当新进程输出内容到 stdoutstderr 时,立刻显示这些内容,你可以这样做:

def print_pipe(type_pipe,pipe):
    for line in iter(pipe.readline, ''):
         print "[%s] %s"%(type_pipe,line),

p = Popen(cmd, bufsize=1024,
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)

t1 = Thread(target=print_pipe, args=("stdout",p.stdout,))
t1.start()
t2 = Thread(target=print_pipe, args=("stderr",p.stderr,))
t2.start()

#optionally you can join the threads to wait till p is done. This is avoidable but it 
# really depends on the application.
t1.join()
t2.join()

在这种情况下,每当有新行写入到 stdoutstderr 时,会有两个线程负责打印这些内容。参数 type_pipe 用来区分这些行是来自 stderr 还是 stdout,这样你就能知道信息的来源。

撰写回答