Как получить данные stdout подпроцесса асинхронно?
Я написал простой скрипт python для своего приложения и предопределил некоторые быстрые команды, такие как 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 и это выход цветной. Есть шансы сохранить цвета на выходе?
Я могу посмотреть на вывод после завершения процесса. Например, сделать работает в течение длительного периода времени, но я вижу выход только после полной компиляции. Как это сделать асинхронно?
6 ответов
Я не уверен в цветах, но вот как опросить 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 будет излучать информацию там.
вы не получаете цвет, потому что cmake
определяет, является ли его stdout терминалом, если нет, он не окрашивает свой собственный выход. Некоторые программы дают вам возможность принудительно выводить раскраску. К сожалению cmake
не делает, так что вам не повезло. Если вы не хотите, чтобы патч cmake
себя.
многие программы делают это, например grep:
# grep test test.txt
test
^
|
|------- this word is red
теперь передайте это кошке:
# grep test test.txt | cat
test
^
|
|------- no longer red
grep
опции --color=always
чтобы заставить цвет:
# grep test test.txt --color=always | cat
test
^
|
|------- red again
Что касается того, как получить результат вашего процесса до его завершения, должно быть возможно сделать это, заменив:
p.stdout.read
С:
for line in p.stdout:
Что касается того, как сохранить цветной выход, в этом нет ничего особенного. Например, если вывод строки сохраняется в файл, то в следующий раз cat <logfile>
выполняется консоль будет интерпретировать escape-последовательности и отображать цвета, как ожидалось.
для CMake в частности, вы можете принудительно выводить цвет с помощью опции CLICOLOR_FORCE=1
:
command = 'make CLICOLOR_FORCE=1'
args = shlex.split(command)
proc = subprocess.Popen(args, stdout=subprocess.PIPE)
затем распечатать как в принято отвечать:
while proc.poll() is None:
output = proc.stdout.readline()
print(output.decode('utf-8'))
если вы расшифровываете к utf-8 перед печатанием, то вы должны увидеть покрашенный выход. Если вы печатаете результат как байтовый литерал (т. е. без декодирования), вы должны увидеть escape-последовательности для различных цветов.
рассмотрите возможность попробовать опцию universal_newlines=True
:
proc = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True)
это вызывает вызов к proc.stdout.readline()
чтобы вернуть строку вместо байтового литерала, вы можете / должны пропустить вызов decode()
.
чтобы сделать асинхронный вывод, сделайте что-то вроде:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
Не уверен, что вы можете захватить цветной выход. Если вы можете получить экранированные цветовые коды, вы можете это сделать.
стоит отметить, что здесь используется script
команда как псевдо-терминал и обнаруживается как tty вместо дескриптора файла перенаправления(канала), см.:
команда 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, которые вы после.
кафе!