【问题标题】:Python subprocess, realtime print with COLORS and save stdoutPython 子进程,使用颜色实时打印并保存标准输出
【发布时间】:2019-11-12 02:13:30
【问题描述】:

在保存结果的同时打印子进程的输出并不是一个新问题,之前已经回答过很多次例如:https://stackoverflow.com/a/28319191/5506400 这对我不起作用,因为我试图保持打印的外壳颜色。例如。当一个人去systemctl status application时,它的印刷品以绿色运行。 上述方法都依赖于从子进程中逐行读取,但在我看来,颜色信息被剥离并丢失了。

我试图制作一个从标准输出打印出来的对象并将它们保存到一个变量中:

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)

但问题是子进程的标准输出需要一个实际的文件:https://stackoverflow.com/a/2298003/5506400

是否可以实时打印子进程的输出,同时保持颜色,并将值存储到变量中(无需通过临时文件)?

【问题讨论】:

    标签: python python-3.x subprocess systemd


    【解决方案1】:

    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
    

    【讨论】:

    • 这在 windows 中不起作用,因为 windows 中不存在 tty termios
    【解决方案2】:

    systemctl 检查输出的去向;如果是 tty,它会显示彩色输出。如果 STDOUT 未附加到 tty,则不显示颜色。

    因此,本质上您需要从源代码执行此操作,即当 STDOUT 不是 tty 时,让 systemctl 发出必要的转义码。

    有办法,来自man systemd

    $SYSTEMD_COLORS
        Controls whether colorized output should be generated.
    

    因此您需要传递SYSTEMD_COLORS 环境变量以使systmectl 返回带有颜色转义的输出。

    你可以这样做:

    os.environ['SYSTEMD_COLORS'] = '1'
    subprocess.run(['systemctl', 'status', 'application'], stdout=subprocess.PIPE)
    

    要让这个命令的环境变量只在之后执行del os.environ['SYSTEMD_COLORS']

    或者只针对单个命令直接在 shell 上运行:

    subprocess.run('SYSTEMD_COLORS=1 systemctl status application', shell=True, stdout=subprocess.PIPE)
    

    【讨论】:

    • 这个答案令人失望,因为它仅解决了systemctl 颜色的问题。在这种情况下,实际发布确切问题产生的答案仅对原始发布者有帮助,并且没有为类似情况提供通用方法。该解决方案更多的是关于系统管理,而不是编程。
    猜你喜欢
    • 1970-01-01
    • 2021-02-06
    • 2013-06-29
    • 2023-02-04
    • 2014-04-29
    • 2012-09-29
    • 1970-01-01
    • 2019-02-24
    • 2016-12-01
    相关资源
    最近更新 更多