Python:即使不包含换行符,也如何重定向子进程输出

问题描述 投票:0回答:1

我有一个Python脚本来启动一个进程(CMake),并将其输出重定向到控制台:

proc = subprocess.Popen([cmake,my_args], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    sys.stdout.write(line.decode('utf-8'))
res = proc.wait()

这很好,并且来自CMake的任何消息都输出到我的控制台。

但是,在某些时候,CMake脚本使用此代码显示了进度:

execute_process(COMMAND ${CMAKE_COMMAND} -E echo_append "Adding modules")
...
execute_process(COMMAND ${CMAKE_COMMAND} -E echo_append "." )
...
execute_process(COMMAND ${CMAKE_COMMAND} -E echo "done\n" )

这很聪明,导致“正在添加模块....”显示在一行上,并且为每个处理的模块添加了一个新的点。

但是由于此输出在完成之前没有换行符,因此只有在添加最后一个模块并显示Python后,我的"done\n"脚本才会报告该输出。我希望我的Python脚本逐点报告此消息,以便可以查看进度。

是否有任何方法可以捕获子流程输出,无论其是否包含新行?

注意:我可以修改PythonCMake脚本...

python cmake subprocess
1个回答
0
投票

完整答案:

这是正确的代码:

import subprocess
import sys

proc = subprocess.Popen([cmake,my_args], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

while True:
    out = proc.stdout.read(1)
    if out == '' and proc.poll() != None:
        break
    if out != '':
        sys.stdout.write(out)
        sys.stdout.flush()

proc.stdout.read(1)确保缓冲区大小为1,并且proc.poll() != None确保在字符之间等待时输出不会停止。另外,我想您可以使用print(out, '')代替:

sys.stdout.write(out)
sys.stdout.flush()

但是我没有时间测试:)

复杂且不完整的答案:

这可能有效,但需要修改。这是一种更“低级”的方法。

您需要在bufsize构造函数中设置subproccess.Popen参数。默认值为-1,这是系统默认缓冲区,在大多数情况下为“行缓冲”。

因此您需要设置bufsize = 0才能获取每个字符。在非常繁忙的应用程序中,这可能会导致性能问题(因为读/写系统调用非常昂贵)

根据the docs

[bufsize将在创建open()管道文件对象时作为stdin/stdout/stderr函数的相应参数提供:

0表示未缓冲(读和写是一个系统调用,并且可以返回短整数)

1表示行缓冲(仅在universal_newlines=True,即在文本模式下可用)

任何其他正值表示使用大约那个大小的缓冲区

bufsize(默认值)表示将使用系统默认值io.DEFAULT_BUFFER_SIZE

© www.soinside.com 2019 - 2024. All rights reserved.