Python 子进程,使用颜色实时打印并保存标准输出
Python subprocess, realtime print with COLORS and save stdout
在保存结果的同时打印子进程的输出并不是一个新问题,之前已经回答过很多次,例如:
这对我不起作用,因为我试图保持打印的 shell 颜色。例如。当出现 systemctl status application
时,它会以绿色打印 运行。
上述方法都是从subprocess中一行一行的读取,但是在我看来颜色信息被剥离掉了。
我试图制作一个对象,它不在标准输出打印中,并将它们保存到一个变量中:
from subprocess import *
import sys
class Tee():
def __init__(self):
self.content = ''
self.stdout = sys.stdout
sys.stdout = self
def __enter__(self):
return self
def __exit__(self, *args):
pass
def __del__(self):
sys.stdout = self.stdout
def write(self, data):
self.content += data
self.stdout.write(data)
def flush(self):
self.content = ''
with Tee() as tee:
# Saves print to tee.content
print("Hello World")
# This line does not save prints to tee.content
run(['apt-get', 'update'])
# raises an error that tee.fileno is not supported
run(['systemctl', 'status', 'nginx'], stdout=tee)
content = tee.content
print("---------------------")
print(content)
但问题是子进程的标准输出需要一个实际文件:
有没有办法实时打印子进程的输出,同时保持颜色,并将值存储到变量(不通过临时文件)?
systemctl
检查输出的去向;如果是 tty,它会显示彩色输出。如果 STDOUT 未连接到 tty,则不会显示颜色。
所以,基本上你需要从源代码中做到这一点,即当 STDOUT 不是 tty 时,systemctl
发出必要的转义码。
有办法,来自man systemd
:
$SYSTEMD_COLORS
Controls whether colorized output should be generated.
所以你需要传递 SYSTEMD_COLORS
环境变量来使 systmectl
return 输出颜色转义。
你可以这样做:
os.environ['SYSTEMD_COLORS'] = '1'
subprocess.run(['systemctl', 'status', 'application'], stdout=subprocess.PIPE)
要让此命令的环境变量仅在之后执行 del os.environ['SYSTEMD_COLORS']
。
或 运行 on shell 直接用于单个命令:
subprocess.run('SYSTEMD_COLORS=1 systemctl status application', shell=True, stdout=subprocess.PIPE)
您无法使用 subprocess
,但 pty
可以。 pty
创建伪终端,因此正在执行的命令检测到它是 运行 tty 并启用彩色输出。
import pty, os
output_bytes = []
def read(fd):
data = os.read(fd, 1024)
output_bytes.append(data)
return data
pty.spawn([command], read)
output = str(output_bytes)
# parse output as you need
在保存结果的同时打印子进程的输出并不是一个新问题,之前已经回答过很多次,例如:
这对我不起作用,因为我试图保持打印的 shell 颜色。例如。当出现 systemctl status application
时,它会以绿色打印 运行。
上述方法都是从subprocess中一行一行的读取,但是在我看来颜色信息被剥离掉了。
我试图制作一个对象,它不在标准输出打印中,并将它们保存到一个变量中:
from subprocess import *
import sys
class Tee():
def __init__(self):
self.content = ''
self.stdout = sys.stdout
sys.stdout = self
def __enter__(self):
return self
def __exit__(self, *args):
pass
def __del__(self):
sys.stdout = self.stdout
def write(self, data):
self.content += data
self.stdout.write(data)
def flush(self):
self.content = ''
with Tee() as tee:
# Saves print to tee.content
print("Hello World")
# This line does not save prints to tee.content
run(['apt-get', 'update'])
# raises an error that tee.fileno is not supported
run(['systemctl', 'status', 'nginx'], stdout=tee)
content = tee.content
print("---------------------")
print(content)
但问题是子进程的标准输出需要一个实际文件:
有没有办法实时打印子进程的输出,同时保持颜色,并将值存储到变量(不通过临时文件)?
systemctl
检查输出的去向;如果是 tty,它会显示彩色输出。如果 STDOUT 未连接到 tty,则不会显示颜色。
所以,基本上你需要从源代码中做到这一点,即当 STDOUT 不是 tty 时,systemctl
发出必要的转义码。
有办法,来自man systemd
:
$SYSTEMD_COLORS
Controls whether colorized output should be generated.
所以你需要传递 SYSTEMD_COLORS
环境变量来使 systmectl
return 输出颜色转义。
你可以这样做:
os.environ['SYSTEMD_COLORS'] = '1'
subprocess.run(['systemctl', 'status', 'application'], stdout=subprocess.PIPE)
要让此命令的环境变量仅在之后执行 del os.environ['SYSTEMD_COLORS']
。
或 运行 on shell 直接用于单个命令:
subprocess.run('SYSTEMD_COLORS=1 systemctl status application', shell=True, stdout=subprocess.PIPE)
您无法使用 subprocess
,但 pty
可以。 pty
创建伪终端,因此正在执行的命令检测到它是 运行 tty 并启用彩色输出。
import pty, os
output_bytes = []
def read(fd):
data = os.read(fd, 1024)
output_bytes.append(data)
return data
pty.spawn([command], read)
output = str(output_bytes)
# parse output as you need