可以拆分/合并subprocess.Popen的输出流吗?
我正在为一个工作流管理器写一个包装类。我想以特定的方式记录一个应用程序的输出(这个应用程序是通过 subprocess.Popen
执行的子进程):
- 子进程的
stdout
输出应该同时写入一个日志文件和父进程的stdout
, - 子进程的
stderr
输出应该写入另一个日志文件,但也要输出到父进程的stdout
。
也就是说,所有来自子进程的输出都应该合并到 stdout
中(就像使用 subprocess.Popen(..., stderr=subprocess.STDOUT)
一样),这样我就可以把 stderr
留给包装类本身的日志消息。另一方面,子进程的输出流应该写入不同的文件,以便进行单独的验证。
我尝试使用一个“分流器”辅助类,将两个流(stdout
和日志文件)连接在一起,这样 Tee.write
就可以同时写入这两个流。然而,这个分流器不能传递给 Popen
,因为“subprocess”使用的是操作系统级别的写入函数(具体可以查看这里:http://bugs.python.org/issue1631)。
我当前解决方案的问题是(下面的代码片段,主要改编自 这里),就是 stdout
上的输出可能不会按正确的顺序出现。
我该如何克服这个问题?或者我应该使用完全不同的方法?(如果我坚持使用下面的代码,如何选择 os.read
中字节数的值?)
import subprocess, select, sys, os
call = ... # set this
process = subprocess.Popen(call, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
logs = {process.stdout: open("out.log", "w"), process.stderr: open("err.log", "w")}
done = {process.stdout: False, process.stderr: False}
while (process.poll() is None) or (not all(done.values())):
ready = select.select([process.stdout, process.stderr], [], [])[0]
for stream in ready:
data = os.read(stream.fileno(), 1)
if data:
sys.stdout.write(data)
logs[stream].write(data)
else:
done[stream] = True
logs[process.stdout].close()
logs[process.stderr].close()
顺便说一下,这个使用 "fcntl" 的解决方案对我没有用。而且我还没弄明白如何将 这个解决方案 适应到我的情况,所以我还没有尝试过。