Подпроцесс Python, печать в реальном времени с ЦВЕТАМИ и сохранение стандартного вывода - PullRequest
2 голосов
/ 01 июля 2019

Печать вывода подпроцесса при сохранении результата не является новой проблемой, и на нее уже много раз отвечали, например: 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

В любом случае можно ли выводить в реальном времени выходные данные подпроцесса, сохраняя цвета, и сохранять значение в переменной (без прохождения временного файла)?

1 Ответ

1 голос
/ 01 июля 2019

systemctl проверяет, куда идет выход; если это tty, он показывает цветной вывод. Если STDOUT не привязан к tty, он не показывает цвет.

Итак, по сути, вам нужно сделать это из источника, т.е. заставить systemctl выдавать необходимые escape-коды, когда STDOUT не является tty.

Есть способ, от 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)

Чтобы иметь env var для этой команды, выполните только del os.environ['SYSTEMD_COLORS'].

Или запустить на оболочке напрямую только для одной команды:

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