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


32

假设我运行一个命令或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
您要在这里解决什么问题?
肯斯特,2015年

3
担心有人会问这个;真的没有,主要是好奇的,希望能增进我对重定向的理解。
KM。

7
你可以把stderred你的shell环境的LD_PRELOAD获取stdoutstderr不同的颜色。在这方面,这是一个相关的问题。
Anko

Answers:


18

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

在上述情况下,您可以做的是与命令一起运行stdoutstderr重定向到其他地方,然后看看会发生什么。或运行两次,一次stdout重定向到/dev/null,一次stderr重定向到/dev/null,然后查看哪种情况会导致文本显示。

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


9

您可以使用重定向标准输出> 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

非常好!如果可以用颜色而不是前缀来突出显示线条,那就太好了。
dotancohen

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

请注意,如果stdout和stderr混合输出,则先打印stdout,然后打印stderr。
nyuszika7h 2015年

5

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

有一些注意事项,主要的问题在其他答案中也有提及:事后您不能这样做。尽管外壳程序负责最初设置它们,但是外壳程序和终端都不知道任意程序如何使用其文件描述符。

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

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


1
请注意,这是一个bash使用while read循环并date为stdout或stderr的每一行运行一个命令的脚本,因此它的效率要比cmd > >(ts '%T O:') 2> >(ts '%T E:')同等效率低得多。
斯特凡Chazelas

1

除了其他答案,指向/proc/$PID/fd(尽管它没有回答问题)很有趣:

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

如您所见,在这里您可以看到为进程打开的文件描述符。0STDIN1STDOUT2STDERR。如果您没有重定向STDOUT或STDERR,则会看到/dev/pts/33(至少在此示例中),因为它们将指向终端。

注意/proc/$PID仅适用于正在运行的进程。在这种情况下,我使用了cat没有参数,因此直到我关闭STDIN。时它才结束。我也已在后台执行了该命令,因此,出于本示例的考虑,我将立即获得PID。


0

不清楚您要问什么,但这可能会有所帮助

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

资源

如果退出代码为0,则仅表示命令已正确执行(stdout),如果退出代码不同于0(stderr),则可以在此处找到含义。


很有意思!我永远不会将退出状态与重定向相关联。零暗示stdout和非零暗示stderr吗?
KM。

7
@KM。,不。我会说它具有很强的相关性,但是没有什么可以阻止程序写入stderr并返回正确的错误代码,或者写入stdout并返回错误的错误代码。实际上,尝试find /root-假设您不是以root身份运行,则应该打印2行-将“ / root”打印到stdout,并将“ find:/ root:权限被拒绝”打印到stderr。并且find返回错误的返回码。
godlygeek

op的问题很明显,那就是如何分辨是stdout还是stderr。
it_is_a_literature

0

通常,STDERR将在程序名称前加一个冒号。

例:

rpm -zq some_utils 
rpm: -zq: unknown option

VS

rpm -ql some_utils 
package some_utils is not installed

-1

要捕获并测试错误输出:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
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.