我正在尝试处理来自stdout
调用的stderr
和subprocess.Popen
,这两个调用都通过subprocess.PIPE
捕获,但是想要处理输出(例如打印它们)在终端上)来了。
我见过的所有当前解决方案都会等待Popen
调用完成,以确保捕获所有stdout
和stderr
,以便它可以处理。
这是一个带有混合输出的示例Python脚本,在实时处理(或尽可能实时)时,我似乎无法复制订单:
$ cat mix_out.py
import sys
sys.stdout.write('this is an stdout line\n')
sys.stdout.write('this is an stdout line\n')
sys.stderr.write('this is an stderr line\n')
sys.stderr.write('this is an stderr line\n')
sys.stderr.write('this is an stderr line\n')
sys.stdout.write('this is an stdout line\n')
sys.stderr.write('this is an stderr line\n')
sys.stdout.write('this is an stdout line\n')
似乎可能有用的一种方法是使用线程,因为那时读取将是异步的,并且可以在subprocess
产生输出时进行处理。
此正常流程的当前实现stdout
首先和stderr
最后,如果输出最初在两者之间交替,则可能是欺骗性的:
cmd = ['python', 'mix_out.py']
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
**kw
)
if process.stdout:
while True:
out = process.stdout.readline()
if out == '' and process.poll() is not None:
break
if out != '':
print 'stdout: %s' % out
sys.stdout.flush()
if process.stderr:
while True:
err = process.stderr.readline()
if err == '' and process.poll() is not None:
break
if err != '':
print 'stderr: %s' % err
sys.stderr.flush()
如果我运行以上(保存为out.py
)来处理上面的mix_out.py
示例脚本,则按顺序处理流(按预期方式):
$ python out.py
stdout: this is an stdout line
stdout: this is an stdout line
stdout: this is an stdout line
stdout: this is an stdout line
stderr: this is an stderr line
stderr: this is an stderr line
stderr: this is an stderr line
stderr: this is an stderr line
我理解一些系统调用可能会缓冲,我对此感到满意,我要解决的一件事就是在发生流时遵循流的顺序。
是否有办法处理stdout
和stderr
,因为它来自subprocess
,而不必使用线程? (代码在无法进行线程处理的受限远程系统中执行。)
需要区分stdout和stderr是必须的(如示例输出中所示)
理想情况下,没有额外的库是最好的(例如我知道pexpect
解决了这个问题)
很多例子都提到select
的使用,但是我没有想出能够保留输出顺序的东西。
答案 0 :(得分:0)
很抱歉,如果我误解了这个问题...但如果您正在寻找一种方式 subprocess.Popen
实时输出到stdout / stderr ,那么你应该能够实现:
import sys, subprocess
p = subprocess.Popen(cmdline,
stdout=sys.stdout,
stderr=sys.stderr)
可能stderr=subprocess.STDOUT
可能会简化您的过滤?
如果那不是您正在/正在寻找的,抱歉。但希望它能满足其他人的需求。
答案 1 :(得分:0)
我在这里找到example的工作(请参阅capture_together.py
的列表)。在Windows和UNIX OS上,混合使用cerr
和cout
作为子进程执行的已编译C ++代码。结果相同
答案 2 :(得分:-1)
我可以使用select.select()
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
**kw
)
while True:
reads, _, _ = select(
[process.stdout.fileno(), process.stderr.fileno()],
[], []
)
for descriptor in reads:
if descriptor == process.stdout.fileno():
read = process.stdout.readline()
if read:
print 'stdout: %s' % read
if descriptor == process.stderr.fileno():
read = process.stderr.readline()
if read:
print 'stderr: %s' % read
sys.stdout.flush()
if process.poll() is not None:
break
将select()
参数(reads
的第一个参数)上的文件描述符传递给select()
并循环遍历它们(只要process.poll()
表示该过程还活着。)
不需要线程。代码改编自此stackoverflow answer