如何异步获取子进程'stdout数据?

问题描述 投票:10回答:6

我为我的应用程序编写了一个简单的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运行很长一段时间但我只能在完全编译后看到输出。如何异步进行?
python asynchronous stdout subprocess
6个回答
12
投票

我不确定颜色,但这里是如何一次轮询子进程的stdout一行:

import subprocess
proc = subprocess.Popen('cmake', shell=True, stdout=subprocess.PIPE)
while proc.poll() is None:
    output = proc.stdout.readline()
    print output

不要忘记从st​​derr读取,因为我确信cmake会在那里发出信息。


4
投票

你没有得到颜色,因为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

2
投票

关于如何在完成之前获取流程的输出,应该可以替换:

p.stdout.read

有:

for line in p.stdout:

关于如何保存彩色输出,没有什么特别之处。例如,如果行输出保存到文件,则下次执行cat <logfile>时,控制台将解释转义序列并按预期显示颜色。


1
投票

特别是对于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()


0
投票

要做异步输出,请执行以下操作:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554

不确定是否可以捕获彩色输出。如果您可以获得转义的颜色代码,您可以。


-1
投票

值得注意的是,使用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!

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