如何判断命令或 shell 脚本的输出是 stdout 还是 stderr

如何判断命令或 shell 脚本的输出是 stdout 还是 stderr

假设我运行一个命令或 shell 脚本,它会给出输出。在不了解此命令或 shell 脚本的内部结构的情况下,如何确定输出是来自stderr还是stdout

例如,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

对比

ls -ld /test
ls: /test: No such file or directory

如何确定第一个命令打印到stdout,第二个命令打印到stderr(是吗?)?

答案1

没有办法知道输出是否已被打印。在这种情况下,stdout和都stderr连接到终端,因此当文本出现在终端上时,有关写入哪个流的信息已经丢失;它们在到达终端之前就被程序组合在一起了。

在上述情况下,您可以做的是运行命令stdoutstderr重定向到不同的位置,看看会发生什么。或者运行两次,一次使用stdout重定向到/dev/null,一次使用stderr重定向到/dev/null,然后查看哪种情况会导致文本显示。

您可以通过在命令行末尾添加来重定向stdout到,也可以通过添加 来重定向到。/dev/null>/dev/nullstderr/dev/null2>/dev/null

答案2

您可以使用 重定向 stdout > file,并使用 重定向 stderr 2> file。许多现代 shell 支持重定向到命令,因此您可以使用sed它来突出显示哪个输出来自哪个流:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

答案3

annotate-output来自 Debian 的脚本devscripts让您有选择地执行此操作:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

第二列分别用O和表示 stdout 和 stderr E

有一些警告,主要的警告如其他答案中所述:事后你不能这样做。尽管 shell 负责最初设置它们,但 shell 和终端都不知道任意程序如何使用其文件描述符。

此方法使用 fifo,写入 fifo 的行为与写入 tty 的行为不同,并且写入两个不同的 fifo 肯定是不同的(潜在的计时/交错问题)。此外,它不适合交互式使用,例如,这annotate-output bash不是一个很好的计划,但它对于许多其他目的很有用。关于着色 stdin/stdout/stderr 的相关问题,有很多很多脚本和 shell 函数的示例,最强大的是标准德德它使用(大多数)程序的运行时修改来修改写入 stderr 的数据。

Anko 链接到的这个问题在相关主题上有很好的答案:对 stdout/stderr 输出进行着色: 我可以将 shell 配置为以不同颜色打印 STDERR 和 STDOUT 吗?

答案4

通常 STDERR 会将程序名称添加到消息前面并带有冒号。

例子:

rpm -zq some_utils 
rpm: -zq: unknown option

VS

rpm -ql some_utils 
package some_utils is not installed

相关内容