Слияние подпроцесса скрипта Python 'stdout и stderr, сохраняя их различимыми

Я хотел бы направить подпроцесс скрипта python 'stdout и stdin в тот же файл. Я не знаю, как сделать линии из двух источников различимыми? (Например, префикс строк из stderr с восклицательным знаком.)

В моем конкретном случае нет необходимости в реальном мониторинге подпроцесса, исполняемый скрипт Python может дождаться окончания его выполнения.

6 Solutions collect form web for “Слияние подпроцесса скрипта Python 'stdout и stderr, сохраняя их различимыми”

 tsk = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.STDOUT) 

subprocess.STDOUT – это специальный флаг, который сообщает подпроцессу маршрутизировать весь вывод stderr в stdout, объединяя ваши два потока.

btw, select не имеет poll () в окнах. subprocess использует только номер дескриптора файла и не вызывает метод записи объекта вывода файла.

для захвата вывода, сделайте что-то вроде:

 logfile = open(logfilename, 'w') while tsk.poll() is None: line = tsk.stdout.readline() logfile.write(line) 

Если вы хотите чередовать, чтобы получить примерно тот же порядок, что и в случае, если вы запустили процесс в интерактивном режиме, вам нужно сделать то, что делает оболочка, и опросить stdin / stdout и написать в том порядке, в котором они участвуют.

Вот код, который делает что-то в соответствии с тем, что вы хотите – в этом случае отправка stdout / stderr в поток информации / ошибок журнала.

 tsk = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.PIPE) poll = select.poll() poll.register(tsk.stdout,select.POLLIN | select.POLLHUP) poll.register(tsk.stderr,select.POLLIN | select.POLLHUP) pollc = 2 events = poll.poll() while pollc > 0 and len(events) > 0: for event in events: (rfd,event) = event if event & select.POLLIN: if rfd == tsk.stdout.fileno(): line = tsk.stdout.readline() if len(line) > 0: logger.info(line[:-1]) if rfd == tsk.stderr.fileno(): line = tsk.stderr.readline() if len(line) > 0: logger.error(line[:-1]) if event & select.POLLHUP: poll.unregister(rfd) pollc = pollc - 1 if pollc > 0: events = poll.poll() tsk.wait() 

В последнее время мне пришлось решить эту проблему, и в большинстве случаев мне потребовалось некоторое время, чтобы получить что-то, что я чувствовал, работая правильно, так что вот оно! (Он также имеет хороший побочный эффект обработки вывода через регистратор python, который я заметил, является еще одним распространенным вопросом здесь, в Stackoverflow).

Вот код:

 import sys import logging import subprocess from threading import Thread logging.basicConfig(stream=sys.stdout,level=logging.INFO) logging.addLevelName(logging.INFO+2,'STDERR') logging.addLevelName(logging.INFO+1,'STDOUT') logger = logging.getLogger('root') pobj = subprocess.Popen(['python','-c','print 42;bargle'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) def logstream(stream,loggercb): while True: out = stream.readline() if out: loggercb(out.rstrip()) else: break stdout_thread = Thread(target=logstream, args=(pobj.stdout,lambda s: logger.log(logging.INFO+1,s))) stderr_thread = Thread(target=logstream, args=(pobj.stderr,lambda s: logger.log(logging.INFO+2,s))) stdout_thread.start() stderr_thread.start() while stdout_thread.isAlive() and stderr_thread.isAlive(): pass 

Вот результат:

 STDOUT:root:42 STDERR:root:Traceback (most recent call last): STDERR:root: File "<string>", line 1, in <module> STDERR:root:NameError: name 'bargle' is not defined 

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

В настоящий момент все остальные ответы не обрабатывают буферизацию на стороне дочернего подпроцесса, если подпроцесс не является скриптом Python, который принимает флаг -u . См. Почему не просто использовать трубу (popen ())?

Чтобы имитировать флаг -u для некоторых программ на основе stdio ( FILE* ), вы можете попробовать stdbuf .

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

 stderr stderr ...large block of stdout including parts that are printed before stderr... 

Вы можете попробовать его со следующей клиентской программой, заметить разницу с / без флага -u ( ['stdbuf', '-o', 'L', 'child_program'] также исправляет вывод):

 #!/usr/bin/env python from __future__ import print_function import random import sys import time from datetime import datetime def tprint(msg, file=sys.stdout): time.sleep(.1*random.random()) print("%s %s" % (datetime.utcnow().strftime('%S.%f'), msg), file=file) tprint("stdout1 before stderr") tprint("stdout2 before stderr") for x in range(5): tprint('stderr%d' % x, file=sys.stderr) tprint("stdout3 after stderr") 

В Linux вы можете использовать pty для получения того же поведения, что и при работе подпроцесса в интерактивном режиме, например, вот ответ измененного @ T.Rojan :

 import logging, os, select, subprocess, sys, pty logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) master_fd, slave_fd = pty.openpty() p = subprocess.Popen(args,stdout=slave_fd, stderr=subprocess.PIPE, close_fds=True) with os.fdopen(master_fd) as stdout: poll = select.poll() poll.register(stdout, select.POLLIN) poll.register(p.stderr,select.POLLIN | select.POLLHUP) def cleanup(_done=[]): if _done: return _done.append(1) poll.unregister(p.stderr) p.stderr.close() poll.unregister(stdout) assert p.poll() is not None read_write = {stdout.fileno(): (stdout.readline, logger.info), p.stderr.fileno(): (p.stderr.readline, logger.error)} while True: events = poll.poll(40) # poll with a small timeout to avoid both # blocking forever and a busy loop if not events and p.poll() is not None: # no IO events and the subprocess exited cleanup() break for fd, event in events: if event & select.POLLIN: # there is something to read read, write = read_write[fd] line = read() if line: write(line.rstrip()) elif event & select.POLLHUP: # free resources if stderr hung up cleanup() else: # something unexpected happened assert 0 sys.exit(p.wait()) # return child's exit code 

Он предполагает, что stderr всегда небуферизован / буферизирован, а stdout – в буфере в линии в интерактивном режиме. Читаются только полные строки. Программа может блокироваться, если на выходе есть строки без конца.

Я предлагаю вам написать свои собственные обработчики, что-то вроде (не проверено, надеюсь, вы поймаете идею):

 class my_buffer(object): def __init__(self, fileobject, prefix): self._fileobject = fileobject self.prefix = prefix def write(self, text): return self._fileobject.write('%s %s' % (self.prefix, text)) # delegate other methods to fileobject if necessary log_file = open('log.log', 'w') my_out = my_buffer(log_file, 'OK:') my_err = my_buffer(log_file, '!!!ERROR:') p = subprocess.Popen(command, stdout=my_out, stderr=my_err, shell=True) 

Вы можете записать stdout / err в файл после выполнения команды. В приведенном ниже примере я использую травление, поэтому я уверен, что смогу прочитать без какого-либо конкретного синтаксического анализа, чтобы различать stdout / err, и в какой-то момент я мог бы выполнить код exit и команду.

 import subprocess import cPickle command = 'ls -altrh' outfile = 'log.errout' pipe = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) stdout, stderr = pipe.communicate() f = open(outfile, 'w') cPickle.dump({'out': stdout, 'err': stderr},f) f.close() 
  • Почему подача stdin на subprocess.Popen вызывает то, что записывается в stdout для изменения?
  • Перенаправление stdio из команды в os.system () в Python
  • Python `print` передает дополнительный текст в sys.stdout?
  • Перехват stdout подпроцесса во время его запуска
  • Модуль readline Python печатает escape-символ во время импорта
  • получение сценария python для печати на терминал без возврата в качестве части stdout
  • Сохранение stdout из subprocess.Popen в файл, плюс запись большего количества материала в файл
  • Передача данных между Python и C # без записи файла
  •  
    Interesting Posts for Van-Lav

    «Побитовое не» в Python, не понимающем дополнения 2

    Force setuptools использовать dependency_links для установки mysqlclient

    Добавление двух объектов pandas.series

    Добавление полосы прокрутки в группу виджетов в Tkinter

    Pandas read_csv ожидает неправильное количество столбцов, с рваным файлом csv

    Для Django 1.7.1 требуется значение по умолчанию для поля, но в базе данных нет записи. Зачем?

    Веб-структуры и доступные библиотеки: Это смелый шаг, чтобы выбрать Node.js вместо Python?

    Попробуйте включить вход на основе столбца и имя файла в Pnadas Dataframe в Python

    Работа с пользовательскими ролями в Django

    создание графиков разметки matplotlib из dataframes в пандах Python

    Получение ошибки: redirect_uri_mismatch URI перенаправления в запросе: http: // localhost: 8080 / oauth2callback не соответствует зарегистрированному URI редиректа

    Многопоточность / многопоточность Python для ускорения копирования файлов

    Библиотека изображений Python 3.1

    Рисование строки, состоящей из нескольких точек с использованием PyQt

    Matplotlib 3DPlot Extra Lines, если размеры не равны

    Python - лучший язык программирования в мире.