Как получить асинхронные данные stdout подпроцесса?

Я написал простой python script для своего приложения и предопределл некоторые быстрые команды, например 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 запускается в течение длительного периода времени, но я могу видеть вывод только после полной компиляции. Как сделать это асинхронно?

Ответ 1

Я не уверен в цветах, но здесь, как опросить подпроцесс stdout по одной строке за раз:

import subprocess
proc = subprocess.Popen('cmake', shell=True, stdout=subprocess.PIPE)
while proc.poll() is None:
    output = proc.stdout.readline()
    print output

Не забудьте также прочитать из stderr, так как я уверен, что cmake выдаст там информацию.

Ответ 2

Вы не получаете цвет, потому что cmake обнаруживает, является ли его stdout терминалом, если он не цвет его собственного вывода. Некоторые программы дают вам возможность форматировать вывод цветов. К сожалению, cmake нет, так что вам там не повезло. Если вы не хотите исправлять cmake самостоятельно.

Это много программ, например grep:

# grep test test.txt
test
 ^
 |
 |------- this word is red

Теперь перетащите его в cat:

# grep test test.txt | cat
test
 ^
 |
 |------- no longer red

grep параметр --color=always, чтобы заставить цвет:

# grep test test.txt --color=always | cat
test
 ^
 |
 |------- red again

Ответ 3

Относительно того, как получить результат вашего процесса до его завершения, должно быть возможно сделать это, заменив:

p.stdout.read

с:

for line in p.stdout:

Что касается сохранения цветного вывода, в этом нет ничего особенного. Например, если вывод строки сохраняется в файл, то в следующий раз выполняется cat <logfile>, консоль будет интерпретировать escape-последовательности и отображать цвета, как ожидалось.

Ответ 4

Для вывода async выполните следующее: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554

Не уверен, что вы можете захватить цветной выход. Если вы можете получить экранированные цветовые коды, вы можете это сделать.

Ответ 5

Здесь стоит упомянуть использование команды script в качестве псевдотерминала и быть обнаруженным как дескриптор файла tty вместо дескриптора перенаправления (pipe), см. bash команда сохранить цвет при конвейерах

Работает как шарм...

В соответствии с примером в вопросе просто давайте 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!