Как получить последние N строк вывода потока stderr подпроцесса? - PullRequest
2 голосов
/ 14 февраля 2011

Я новичок в Python, пишу скрипт на Python (2.7), который должен выполнять несколько внешних приложений, одно из которых записывает много выходных данных в свой поток stderr.То, что я пытаюсь выяснить, - это краткий и лаконичный способ (в Python) получить последние N строк из выходного потока stderr этого подпроцесса.

В настоящее время я запускаю это внешнее приложение из моего скрипта Python, напримерИтак:

p = subprocess.Popen('/path/to/external-app.sh', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()

if p.returncode != 0:
    print "ERROR: External app did not complete successfully (error code is " + str(p.returncode) + ")"
    print "Error/failure details: ", stderr
    status = False
else:
    status = True

Я хотел бы захватить последние N строк вывода из потока stderr, чтобы их можно было записать в файл журнала или отправить по электронной почте и т. д.

Ответы [ 2 ]

3 голосов
/ 14 февраля 2011
N = 3 # for 3 lines of output
p = subprocess.Popen(['/path/to/external-app.sh'], 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()

if p.returncode != 0:
    print ("ERROR: External app did not complete successfully "
           "(error code is %s)" % p.returncode)
    print "Error/failure details: ", '\n'.join(stderr.splitlines()[-N:])
    status = False
else:
    status = True
1 голос
/ 14 февраля 2011

Если весь вывод не может быть сохранен в ОЗУ, то:

import sys

from collections import deque
from subprocess  import Popen, PIPE
from threading   import Thread

ON_POSIX = 'posix' in sys.builtin_module_names

def start_thread(func, *args):
    t = Thread(target=func, args=args)
    t.daemon = True
    t.start()
    return t

def consume(infile, output):
    for line in iter(infile.readline, ''):
        output(line)
    infile.close()

p = Popen(['cat', sys.argv[1]], stdout=PIPE, stderr=PIPE,
          bufsize=1, close_fds=ON_POSIX)

# preserve last N lines of stdout,  print stderr immediately
N = 100 
queue = deque(maxlen=N)
threads  = [start_thread(consume, *args)
            for args in (p.stdout, queue.append), (p.stderr, sys.stdout.write)]
for t in threads: t.join() # wait for IO completion

print ''.join(queue), # print last N lines
retcode = p.wait()
...