Python 3:我可以 运行 一个子进程并获得它的输出,而它不知道它正在被管道传输吗?

Python 3: Can I run a subprocess and obtain its output, without it knowing that it is being piped?

我正在编写一个调用 ls 的程序,如下所示:

import subprocess as sp
sp.run(['ls', '--color=auto'], stdout=sp.PIPE)

问题是 ls 检测到它的输出正在被管道传输,所以它没有用颜色装饰它的输出。但我想以某种方式欺骗命令认为它正在输出到 tty,从而显示颜色。我需要捕获输出的原因是因为我想在将输出显示给用户之前额外处理它。

我试图将 sys.stdout 重定向到 StringIO 对象,然后在没有管道的情况下调用 sp.run,但它不起作用:

import sys, subprocess as sp
from io import StringIO
from contextlib import redirect_stdout

with StringIO() as buf, redirect_stdout(buf):
    sp.run(['ls', '--color=auto'])
    output = buf.getvalue()

processed_output = process_in_some_way(output)
print(processed_output)

这里,sp.run命令输出到stdout,output为空,表示重定向没有生效。

注意:由于一些实际限制,我不能将--color=auto替换为--color=always

您需要在此处使用充当终端的第 3 方实用程序(从程序 运行 的角度来看),因此它会看到它有一个 TTY,然后发出输出写入该终端到常规标准输出。

用于这项工作的广泛使用且易于使用的工具(包含在 expect 套件中)是 unbuffer。因此:

import subprocess as sp
sp.run(['unbuffer', 'ls', '--color=auto'], stdout=sp.PIPE)