Python 子进程日志和显示 Shell 问题

Python subprocess Log and Display in Shell Issues

我有一个 python 脚本,其中我 运行 一个带有 subprocess.Popen() 的外部存档命令。然后我将 stdout 传送到一个 sys 写入和一个日志文件(见下面的代码),因为我需要打印和记录输出。外部命令输出进度,如 "Writing Frame 1 of 1,000",我希望在我的日志中。

到目前为止,我可以通过包含“stdout=subprocess.PIPEstderr=subprocess.PIPE”来大块地 display/write,但随后用户认为脚本无法正常工作。或者我只有“stdout=subprocess.PIPE”进度 "Writing of Frame..." 不在日志文件中。

有什么想法吗?

我的脚本看起来像这样:

archive_log = open('archive.log', 'w')
archive_log.write('Archive Begin')
process_archive = subprocess.Popen(["external_command", "-v", "-d"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) #Archive Command

for line in process_archive.stdout:
    sys.stdout.write(line)
    archive_log.write(line)

archive_log.write('Archive End')
archive_log.close()

听起来您只是想将子进程的标准输出和标准错误合并到一个管道中。为此,作为 the docs explain,您只需传递 stderr=subprocess.STDOUT.


另一方面,如果您想独立地从两个管道读取数据,而不阻塞其中任何一个,那么您需要一些明确的异步性。

一种方法是只创建两个线程,一个在 proc.stdout 上阻塞,另一个在 proc.stderr 上阻塞,然后让主线程 join 两个线程. (您可能希望在每个线程的 for 主体内加一个锁;这是确保以原子方式并以相同顺序在标准输出和文件中写入行的唯一方法。)

或者,许多反应堆类型的异步 I/O 库,包括 stdlib 自己的 asyncio(如果您使用的是 3.4+)和主要的第三方库,如 Twisted,可用于多路复用多个子流程管道。

最后,至少如果你在 Unix 上,如果你理解所有的细节,你可能只用 selectselectors 就可以做到。 (如果这不能让你说 "Aha, I know how to do it, I just have a question about one of the details",请忽略这个想法并使用其他两个中的一个。)


很明显,您确实确实需要这里的 stderr。从你的问题:

Or I just have "stdout=subprocess.PIPE" the progress "Writing of Frame..." aren't in the log file.

这意味着子进程正在将这些消息写入 stderr,而不是 stdout。因此,当您不捕获 stderr 时,它只是传递到终端,而不是被您的代码捕获并写入终端和日志。

很明显,您确实确实需要它们合并或异步处理:

I can either have it display/write in large blocks by including "stdout=subprocess.PIPE, stderr=subprocess.PIPE", but then the user thinks the script isn't working.

用户认为脚本不工作的原因是,虽然您没有向我们展示执行此操作的代码,但很明显您在 stdout 上循环,然后在 stderr 上循环。这意味着在 stdout 完成之前不会显示进度消息,因此用户会认为脚本不工作。

您有没有使用 check_call and the syslog 模块来执行此操作的原因?

您可能还想像这样使用 with

with open('archive.log', 'w') as archive:`
  do stuff

您将受益于文件自动关闭。