如何异步获取子进程'stdout数据?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何异步获取子进程'stdout数据?相关的知识,希望对你有一定的参考价值。
我为我的应用程序编写了一个简单的python脚本,并预定了一些快速命令,如make等。
我编写了一个运行系统命令的函数(linux):
def runCommand(commandLine):
print('############## Running command: ' + commandLine)
p = subprocess.Popen(commandLine, shell = True, stdout = subprocess.PIPE)
print (p.stdout.read().decode('utf-8'))
一切都很好,除了一些事情:
- 我正在使用cmake,它的输出是彩色的。有没有机会在输出中保存颜色?
- 我可以在流程完成后查看输出。例如,make运行很长一段时间但我只能在完全编译后看到输出。如何异步进行?
我不确定颜色,但这里是如何一次轮询子进程的stdout一行:
import subprocess
proc = subprocess.Popen('cmake', shell=True, stdout=subprocess.PIPE)
while proc.poll() is None:
output = proc.stdout.readline()
print output
不要忘记从stderr读取,因为我确信cmake会在那里发出信息。
你没有得到颜色,因为cmake
检测到它的stdout是否是一个终端,如果不是它没有为自己的输出着色。某些程序为您提供强制着色输出的选项。不幸的是cmake
没有,所以你在那里运气不好。除非你想自己修补cmake
。
很多程序都这样做,例如grep:
# grep test test.txt
test
^
|
|------- this word is red
现在把它管到猫:
# grep test test.txt | cat
test
^
|
|------- no longer red
grep
选项--color=always
强制颜色:
# grep test test.txt --color=always | cat
test
^
|
|------- red again
关于如何在完成之前获取流程的输出,应该可以替换:
p.stdout.read
有:
for line in p.stdout:
关于如何保存彩色输出,没有什么特别之处。例如,如果行输出保存到文件,则下次执行cat <logfile>
时,控制台将解释转义序列并按预期显示颜色。
特别是对于CMake,您可以使用选项CLICOLOR_FORCE=1
强制颜色输出:
command = 'make CLICOLOR_FORCE=1'
args = shlex.split(command)
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
然后像在accepted answer中一样打印:
while proc.poll() is None:
output = proc.stdout.readline()
print(output.decode('utf-8'))
如果在打印前解码为utf-8,则应看到彩色输出。如果您将结果打印为字节文字(即不解码),您应该看到各种颜色的转义序列。
考虑尝试选择universal_newlines=True
:
proc = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True)
这导致调用proc.stdout.readline()
返回一个字符串而不是字节文字,因此你可以/必须跳过调用decode()
。
要做异步输出,请执行以下操作:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
不确定是否可以捕获彩色输出。如果您可以获得转义的颜色代码,您可以。
值得注意的是,使用script
命令作为伪终端并被检测为tty而不是重定向(管道)文件描述符,请参阅:bash command preserve color when piping
奇迹般有效...
根据问题中的例子,让script
执行cmake
:
import subprocess
proc = subprocess.Popen('script cmake', shell=True, stdout=subprocess.PIPE)
while proc.poll() is None:
output = proc.stdout.readline()
print output
这使得cmake
认为它正在从一个终端执行,并将产生你所追求的ANSI糖果。
的nJoy!
以上是关于如何异步获取子进程'stdout数据?的主要内容,如果未能解决你的问题,请参考以下文章
在 boost 进程异步子进程中 run() 之后是不是需要 wait()?