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

KM.*_*KM. 39 io-redirection

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

例如,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /
Run Code Online (Sandbox Code Playgroud)

对比

ls -ld /test
ls: /test: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我如何确定第一个命令打印到stdout了第二个stderr(做了吗?)?

god*_*eek 23

一旦输出已经打印,就无法判断。在这种情况下,stdoutstderr都连接到终端,因此当文本出现在终端上时,有关写入哪个流的信息已经丢失;它们在进入终端之前被程序组合。

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

您可以重定向stdout/dev/null通过黏合>/dev/null在命令行的末尾,你可以重定向stderr/dev/null加入2>/dev/null


Mar*_*ick 15

您可以使用 重定向标准输出> file,并使用 重定向标准错误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
Run Code Online (Sandbox Code Playgroud)

  • @dotancohen:一个可以!例如,`(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/. */\x1b[31m&\x1b[0m/')` (4认同)

mr.*_*tic 6

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
Run Code Online (Sandbox Code Playgroud)

第二列分别用O和表示标准输出和标准错误E

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

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

Anko 链接到的这个问题在相关主题上有很好的答案:着色 stdout/stderr 输出:Can I configure my shell to print STDERR and STDOUT in different color ?

  • 请注意,这是一个使用 while read 循环并为 stdout 或 stderr 的每一行运行一个 date 命令的 bash 脚本,因此它的效率比 cmd >>(ts '%TO: ') 2> >(ts '%TE:')` 等效。 (2认同)