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

时间:2012-01-23 19:49:09

标签: python asynchronous stdout subprocess

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

6 个答案:

答案 0 :(得分: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会在那里发出信息。

答案 1 :(得分:4)

你没有获得颜色,因为cmake检测到它的标准输出是否是一个终端,如果不是它没有为自己的输出着色。某些程序为您提供强制着色输出的选项。不幸的是cmake没有,所以你在那里运气不好。除非您想自己修补cmake

许多程序都这样做,例如grep:

# grep test test.txt
test
 ^
 |
 |------- this word is red

现在将它传递给cat:

# grep test test.txt | cat
test
 ^
 |
 |------- no longer red

grep选项--color=always强制使用颜色:

# grep test test.txt --color=always | cat
test
 ^
 |
 |------- red again

答案 2 :(得分:2)

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

p.stdout.read

使用:

for line in p.stdout:

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

答案 3 :(得分: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()的调用。

答案 4 :(得分:0)

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

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

答案 5 :(得分:-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!