如何异步获取子进程'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

不要忘记从st​​derr读取,因为我确信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()?

合并Python脚本的子进程'stdout和stderr,同时保持它们可区分

Python:在记录内存时获取子进程 STDOUT

使用 Python 子进程通信方法时如何获取退出代码?

捕获stdout以获取远程进程的子进程

如何在Python中异步记录stdout / stderr?