进度报告/记录信息是否属于stderr或stdout?


75

是否有正式的POSIX,GNU或其他指南,说明应在何处打印进度报告和日志记录信息(如“ Doing foo; foo done”之类的内容)?就个人而言,我倾向于将它们写入stderr,以便可以重定向stdout并仅获取程序的实际输出。最近有人告诉我,这不是一个好习惯,因为进度报告实际上不是错误,而应该仅将错误消息打印到stderr。

这两个职位都很有意义,当然您可以根据自己的工作细节选择一个或两个,但是我想知道是否有一个普遍接受的标准。在POSIX,GNU编码标准或任何其他这样的最佳实践列表中,我找不到任何特定的规则。

我们有一些类似的问题,但它们不能解决这个确切的问题:

那么,是否有关于打印进度报告和其他信息(不在程序实际输出中的部分)的官方规定?


26
将微调器等stdout与结果一起打印是使结果无用的安全方法。如果您需要将结果传送到其他程序,则该程序需要将结果与微调器分开。另外,如果将输出重定向到文件,则将看不到微调框。恕我直言。
佐藤桂

2
@SatoKatsura是的,这也是我的意见,这就是为什么我要在stderr上打印这样的内容。但是,我所工作的公司的CTO认为打印到stderr表示出现问题。我大胆地声称POSIXWay®正在打印到stderr,他叫我出来。鉴于他对我有20多年的经验,我想看看我是否可以找到某种“官方”指导方针。
terdon

与Sato Katsura所说的一样,stdout实际上是剔除微调器和其他有用信息的一种安全正确的方法,但是正如许多程序员所说的那样,“沉默是黄金。如果一切正常,什么也不输出。因此,实际上,由于定义模糊,stderr总是被用来做,而且stdout可能会破坏管道顺序
。。

6
@七,我想你误会了;佐藤说使用stdout是不安全的(“使结果无用的安全方法”)。
史蒂芬·基特

1
一种可能的“一刀切”解决方案将是仅用于stderr报告错误消息,除非使用了--verbose标志(此时还包括进度报告)。
Gaurav

Answers:


27

Posix 因此定义了标准流:

在程序启动时,应预定义三个流,而不必明确打开它们:标准输入(用于读取常规输入),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。打开时,标准错误流未完全缓冲;当且仅当可以确定该流不引用交互式设备时,标准输入流和标准输出流才被完全缓冲。

GNU C库描述了同样的标准流:

变量:FILE * stdout
标准输出流,用于程序的常规输出。

变量:FILE * stderr
标准错误流,用于程序发出的错误消息和诊断。

因此,除了“常规/正常输出”和“诊断/错误输出”之外,标准定义对流的使用几乎没有指导。在实践中,通常将这两个流中的一个或两个都重定向到文件和管道,这会导致进度指示器出现问题。 。一些系统甚至监视 stderr输出,并认为这是问题的征兆。因此,在任何一个流上纯辅助进度信息都是有问题的。

重要的是要认识到进度输出仅适用于交互式流,而不是将进度指示器无条件地发送到任一标准流。考虑到这一点,我建议仅在检查流是否是交互式的(例如,使用)或由命令行选项显式启用后,才编写进度计数器。这对于依靠终端更新行为来理解进度表的进度表尤为重要,例如进度条%。isatty()

对于某些非常简单的进度消息(“开始X” ...“用X完成”),甚至对于非交互式流也包括输出是更合理的。在这种情况下,请考虑用户如何与流进行交互,例如使用进行搜索grep或分页,less或使用进行监视tail -f。如果在这些情况下查看进度消息是有意义的,那么从中将更容易使用它们stdout


谢谢,GNU准则是我所追求的。但是,我意识到我的问题有点误导。当我提到“进度报告”时,我同时想到的N% donedoing foofoo done。后者应始终保留,因为它们在重定向到文件时用于调试。因此,您关于检查流是否为交互式的建议不适用(尽管通常是一个很好的主意)。
terdon

阿感谢澄清,这是从,就像你在像软件看到“%完成”和散列标记进度条的东西有点不同curlyum。在这种情况下,我会考虑用户是否以及如何将要通过输出交互grepless或类似的工具。
Bradd Szonye,2013年

更新了答案以纳入上述说明。
Bradd Szonye,2013年

71

POSIX 将标准错误定义为

用于编写诊断输出

这不仅限于将其用于错误消息。我会将进度信息视为诊断输出,因此它属于标准错误。


8
在Python中,FWIW stdout默认情况下是行缓冲的,而stderr没有缓冲的,因此stderr编写不包含换行符的进度文本/小节/微调框是自然的选择。(如果您在上面写了这样的文本,则stdout需要弄乱进度输出调用stdout.flush()以使其可见)。
下午16年

12
@ PM2Ring不是特定于Python的,POSIX以这种方式定义了流。
史蒂芬·基特

4
@ PM2Ring:写入时stdout,如果您希望进度报告在重定向后实时实时显示,即使您的文本包含换行符,也需要刷新。

@Hurkyl啊,好点。我没有考虑重定向。
下午16年

1
@W,是吗?否。如果退出状态为0,Ansible会吞下stderr文本。该声明完全是错误的。
查尔斯·达菲,

10

POSIX在Shell and Utilities 1.4中对“诊断信息”的含义更为具体:实用程序描述默认值(强调我的):

斯特德

STDERR部分描述了实用程序的标准错误输出。仅描述实用程序有意发送的那些消息。使用终端处理标准错误可能会导致在后台使用时,任何写入标准错误输出的标准实用程序都将停止。因此,应用程序不应在脚本中使用交互功能放置在后台。

对于大多数实用程序,诊断消息的格式未指定,但是此卷POSIX.1-2008未指定格式的诊断消息和信息消息的语言和文化惯例应受LC_MESSAGES和[XSI]设置的影响。 ] NLSPATH。[选项结束]

标准实用程序的指定标准错误输出应不依赖于POSIX.1-2008的本卷中定义的环境变量的存在或值,除非此POSIX.1-2008的卷中提供了环境变量。

默认行为:当本节被列为“标准错误应仅用于诊断消息。”时,这意味着,除非另有说明,否则仅当退出状态指示错误,才将诊断消息发送为标准错误。发生了故障,并且如本POSIX.1-2008卷所述使用了该实用程序。

当本节被列为“未使用”时,表示按照本POSIX.1-2008卷中的说明使用实用程序时,不应使用标准错误。

IANASL,但我的解释是,仅当实用程序将返回错误退出代码时,stderr才会输出。由于这不应该是成功执行事件的正常过程,因此除非出现错误(除非除非另外指定,否则),否则POSIX实用程序不应打印任何进度信息


我理解这是在描述每个POSIX实用程序的规范中给出的“ STDERR”部分的含义,而不是作为标准错误用法的一般定义。我不认为terdon在这里编写标准的POSIX实用程序;-)。
史蒂芬·基特

1
@StephenKitt也不这样做。但是他正在与CTO争论,CTO表示stderr输出表明出现了问题,该标准确实支持他的默认行为。
muru

1
它仅支持声明作为POSIX实用程序的默认行为,甚至仅在特定情况下(使用提及短语的实用程序)才支持该声明。POSIX的这部分不是规范性的(AIUI),它是一个模板:它告诉您如何阅读实用程序规范,没有指定实用程序的行为。具体来说,它定义了短语“标准错误仅应用于诊断消息”的含义。和“未使用”。在实用程序规范的“ STDERR”部分中。每个实用程序都指定其行为,并且可以将这些短语用作速记。
史蒂芬·基特

@StephenKitt不会改变我的观点。POSIX实用程序a)不会输出到stderr,b)仅在出现问题时将其用于诊断消息,c)即使没有问题也仅将其用于诊断消息,并且d)将其用于其他消息。我说过,除非另有说明(c,d),否则只有在出现问题时(a,b)才将其用于诊断消息。现在,我声称这是默认值,很明显是默认值,因为这就是它的模板。
muru

2
好吧,我想说的是“除非另有说明”,这是一个相当重要的警告:POSIX实用程序可以很好地指定它输出有关其标准错误的进度信息,并且符合标准。没错,有趣的是,“默认行为”(仍需要在相关部分中进行具体说明)是仅在退出代码还指示错误的情况下才使用标准错误。但这不是限制性的。
史蒂芬·基特

7

根据排除的原则,它只能进入stderr。是的,我知道您问过一个正式的规范,除了Stephen Kitt给出的指向POSIX规范的链接之外,我无法向您介绍它,该声明指出stderr用于诊断。

更重要的一点是stdin和stdout具有不允许将进度报告打印到stdout的功能-它们当然形成了管道序列,在Unix shell命令中这不仅是副作用,而且是强大的流水线方法的核心。

所以。程序的真正“有效负载”不属于stdout。如果您的程序没有输出,那么什么都不应该进入标准输出。这使得标准错误的一切,包括进度报告。

当然,这留下了一个漏洞-最好有一个“ stdfluff”或类似的东西,既不是输出也不是错误,而是用于进度报告,调试等。实际上,没有什么可以阻止您执行此操作,即可以将进度打印到文件描述符3中。示例:

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'

这不会产生任何输出。(*)

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'  3>&1
hello

这将打印到fd-3,该文件将重定向到stdout。

(*)第一个示例不产生任何输出,但仍然有些牵强。的open失败,$!将包含no such file or directory; 仅以此为例,认真使用这种方式当然是不重要的。在实际程序中,如果您想走这条路,则可以测试是否/dev/fd/3可用,并以此作为是否激活进度报告的提示。您必须尽早这样做,以免您自己open对真实文件等感到困惑。


什么fd-3啊 第三张软盘?
彼得·莫滕森

文件描述符3,@ PeterMortensen
AnoE

-1

如果用户使用了该用法消息,则应该将其发送到stdout;如果用户输入--help了错误,则应将其发送到stderr。无条件地将其打印到stderr是令人讨厌的,因为这使使用pager / grep / etc进行查看变得更加困难。

另外,我可以建议第三种方法:打开/ dev / tty获取进度报告/ spinners / etc。


6
抱歉,但这不能回答问题。我专门要求提供官方指南,而不是意见。无论如何,即使我征求意见,您在回答的问题也不同。我根本不是在谈论--help或帮助消息。请重新阅读问题。
terdon

您提到“使用信息”,我认为这是您问题的一部分,而不仅仅是您链接的其他问题的标题。我不明白您为什么认为为此存在“官方准则”。谁有权制造它们?
Random832 '16

3
我不知道他们这样做,所以才问。对于官方而言,POSIX标准具有有关程序行为方式的各种详细信息的规范。正如斯蒂芬在回答中所指出的那样,其中包括对应该去stderr的内容的模糊建议。GNU编码标准也可以有类似的东西。基本上,任何组是活动的,为* nix的生态系统产生的代码可能有一个标准,我会感兴趣的
terdon

@terdon可以使用现有程序的示例吗?curl,wget和pv都使用stderr,其中wget和pv使它以tty为条件,而curl使它以stdout为条件而不是tty。
Random832 '16

4
另外,听起来您的CTO认为调用程序应该对stderr上的数据存在做出反应,这意味着发生了错误,而不是查看退出状态。这绝对是一种不好的做法(并且比检查退出状态还要难写),并且可能是使他信服的更好角度。
Random832 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.