如何获取子进程stderr流输出的最后N行?

2 投票
2 回答
5717 浏览
提问于 2025-04-16 11:48

我是一名Python新手,正在写一个Python(2.7)脚本,这个脚本需要执行一些外部应用程序,其中一个会在错误输出流中写很多内容。我想弄清楚用Python怎么简洁明了地获取这个子进程的错误输出流中的最后N行。

目前,我是这样从我的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行,这样我就可以把这些内容写入日志文件或者发邮件等等。

2 个回答

1

如果整个输出不能存储在内存里,那么:

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()
5

在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们写的代码有bug,或者是使用的工具和环境不兼容。解决这些问题通常需要我们仔细检查代码,找出错误的地方,并进行修正。

另外,了解一些基本的调试技巧也很重要。调试就是找出代码中问题的过程。我们可以通过打印一些信息到屏幕上,或者使用调试工具来逐步检查代码的执行情况。这样可以帮助我们更快地找到问题所在。

总之,编程就像解谜一样,需要耐心和细心。遇到问题时,不要急于放弃,慢慢分析,通常就能找到解决办法。

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

撰写回答