何时使用sys.stdout而不是sys.stderr?

6

我的老板让我查看一些旧代码,其中所有内容都被发送到stderr。我知道stderr应该包含警告和错误信息,但是什么情况下它们应该真正地发送到stdout呢?

这个程序是一个服务。它发送到stderr的一些消息是:

if pid is None:
    message = "pidfile {0} is not running. \n"
    sys.stderr.write(message.format(self.pidfile))

所以这个是输出,对吧?关于成功或失败的消息应该发送到标准输出(stdout),因为它不是错误吗?

然后我还有另一个异常:

except OSError as err:
    sys.stderr.write('fork #1 failed: {0}\n'.format(err))
    sys.exit(1)

这个例子是一个异常情况,所以应该被发送到stderr,因为它是一个错误?还是应该发送到stdout,因为它只是输出一条消息,说明程序失败了?

我知道stdout和stderr是什么——在提问之前我读了很多。我的问题在于能否确定哪些消息应该发送到stderr——只有致命错误,还是任何类型的错误消息都应该发送到stderr?

这两个示例都是错误消息,但其中一个只是“程序没有运行”。我很难选择这种消息应该发送到哪里。


2
可能是关于stdin、stdout和stderr的困惑?的重复问题。 - wpercy
6
致命错误应该被发送到stderr。正常输出应该被发送到stdout。对于信息性的消息,存在一定的灰色地带,但通常如果它们会使输出无法使用,则不应该发送到stdout。人们经常将stdout重定向到文件,将stderr发送到终端或日志文件中。因此,您需要决定哪种分割方式最合理。 - Tom Karzes
1
@TomKarzes:将其发布为答案。比重复问题更具信息价值。 - Karoly Horvath
3
把标准输出想象成你的程序“做了什么”,把标准错误想象成你的程序“如何做到的”。 - chepner
4
程序输出的实际数据应该发送到stdout,所有元数据,如错误消息和进度报告应该发送到stderr。因此,“fork #1 failed”应该发送到stderr,类似“fork #1 succeeded”的内容也应该发送到stderr。"pidfile {0} is not running" 也应该发送到stderr。 - PM 2Ring
显示剩余2条评论
2个回答

8
致命错误应该被输出到stderr,正常的输出应该被发送到stdout。
对于信息性消息来说存在一个灰色地带,但通常情况下,如果它们会使输出无法使用,则不应将它们发送到stdout。人们通常将stdout重定向到文件,将stderr重定向到终端或日志文件。
你需要决定哪种分割方式最合理。

4
我喜欢这样想:标准输出是用于你的程序做什么,而标准错误则是用于如何执行它。 - chepner
明白了。第一个只是输出,说明它没有运行,因此不是错误消息。另一个作为致命错误应该发送到stderr。 - DKage
@chepner 非常有帮助。我会尝试将其用作其他方法的模板。谢谢大家。 - DKage
3
@Dkage,"stderr"不仅仅是用于错误消息;它适用于元数据的一般情况。任何具有信息性而非实际输出数据(您希望在另一个程序中解析您生成的内容的数据)的东西都应该放在"stderr"中。 - Charles Duffy
@CharlesDuffy,你能提供最后一个声明的来源吗?我的意思是,在Python中也是这样设计的吗?我认为这将回答我的问题:https://dev59.com/fH8QtIcB2Jgan1zn_-3e - Heberto Mayorquin
1
@HebertoMayorquin,标准输出和标准错误流的约定是由操作系统定义的,而不是由任何特定的编程语言定义的:操作系统的约定定义了在该操作系统上运行的应用程序应该如何行事,您的程序正在UNIX上运行,并且期望遵守UNIX约定,无论使用什么语言编写。请参见https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html中的第2.5节(我在上面使用了“信息性”的词,但正式定义的词是“诊断性”)。 - Charles Duffy

8
已经给出了正确的答案,但是我持有更极端的观点...
我认为把stdoutstderr想象成“标准输出”和“标准非输出”会有所帮助。你说你认为消息“应该被发送到stdout,因为它不是一个错误”,但这是反向的:stdout是难以进入的流,而不是stderr
除非可以证明其属于期望的输出部分(即用户实际需要的最终产品),否则消息应该被发送到stderr(或日志文件,或任何除stdout之外的东西)。如果不能用以“用户请求...”开头的句子证明其包含在内,则不要使用它来污染stdout。(管道中的下一个进程会感谢你。)
很可能,你的用户没有运行程序,因为他们想看旋转的棒子,或读一打“尝试重新连接”的消息,甚至是了解哪些进程失败了,所以这些消息不应出现在stdout中。
最后,有些消息既不应该发送到任何一个输出流。由于假定用户正在阅读stderr,因此请尝试将其输出限制为用户当前关心的事情。除非用户通过升高详细程度(通常为--verbose--debug)来请求它们,否则请勿在其中包含“情况正常”的消息。至少要允许用户使用--quiet--silent选项关闭非错误消息。大多数“信息”消息应该发送到日志文件而不是控制台。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接