【问题标题】:subprocess stderr vs sys.stderr子进程 stderr 与 sys.stderr
【发布时间】:2018-10-12 13:19:34
【问题描述】:

我不确定这个问题是 Python 还是 shell 问题。

我有一个 Python 程序,它在命令上使用子进程调用,该命令可以在 stderr 上发出错误消息。我自己的程序也使用 sys.stderr 来记录错误。这是一个简单的例子,命令 (ls *.foobar) 失败:

import sys,subprocess

sys.stderr.write("--Hello\n")
try:
    subprocess.check_call("ls *.foobar",shell=True)
except subprocess.CalledProcessError as e:
    sys.stderr.write("Command failed\n")
sys.stderr.write("--Bye\n")

当我运行此代码时,控制台上的输出(来自 stderr)如下:

--你好
ls: 无法访问 '*.foobar': 没有这样的文件或目录
命令失败
--再见

如果我将 stderr 重定向到一个文件(例如,使用 python myscript.py 2> 日志),该文件包含以下内容:

ls: 无法访问 '*.foobar': 没有这样的文件或目录
--你好
命令失败
--再见

有没有办法保持文件中消息的顺序(除了在子进程调用中对文件使用 stderr 的显式重定向)?

这个问题类似于一些标准的 stdout/stderr 问题,但在这里,一切都应该在 stderr 上。

【问题讨论】:

  • 记录在案:这种行为并不总是发生,它不是确定性的(例如在我的系统上它现在没有)。请参阅 Martin 的回复,了解其发生的原因。

标签: python stderr


【解决方案1】:

您需要将数据写入器刷新stderr 描述符:

sys.stderr.write("--Hello\n")
sys.stderr.flush()

stdio 在连接到终端时是行缓冲的,在连接到管道时使用固定缓冲区。您正在编写一个\n 换行符,它在连接到终端时会触发刷新,但是如果没有逐行刷新,您对stderr 的写入不足以在 Python 退出时在最终刷新之前触发缓冲区刷新。

如果您使用print(..., file=sys.stderr),您可以通过添加flush=True 来告诉print() 发出flush() 调用:

print("--Hello", file=sys.stderr, flush=True)

处理此问题的另一种方法是“捕获并释放”子进程的 stderr 输出:

sys.stderr.write("--Hello\n")
try:
    subprocess.check_call("ls *.foobar", shell=True, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
    sys.stderr.write(e.stderr)
    sys.stderr.write("Command failed\n")
sys.stderr.write("--Bye\n")

添加的stderr=subprocess.PIPE 告诉subprocess 捕获命令的stderr 输出,您可以找到该输出作为CalledProcessError 异常的e.stderr 属性。

【讨论】:

    猜你喜欢
    • 2020-07-22
    • 2023-04-06
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-07
    • 2020-06-23
    相关资源
    最近更新 更多