我不确定这个问题是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上。
答案 0 :(得分:4)
您需要 flush 数据写入器到stderr
描述符:
sys.stderr.write("--Hello\n")
sys.stderr.flush()
stdio连接到终端时是行缓冲的,连接到管道时是使用固定缓冲的。您正在编写一个\n
换行符,当连接到终端时会触发刷新,但是如果没有该行刷新,您将无法向stderr
写入足够多的字符以在最终刷新之前触发缓冲区刷新当Python退出时。
如果您使用print(..., file=sys.stderr)
,则可以通过添加print()
来告诉flush()
发出flush=True
呼叫:
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输出,并且您可以找到该输出作为e.stderr
异常的CalledProcessError
属性。