在 Linux 下,把命令的输出重定向到文件是一个很常见的操作,但如何正确区分 stdoutstderr 可不是一件容易的事。初学者如果不仔细理解概念,直接按照直观来理解的话,对于这个问题是非常容易混淆的,我们来看这样一个小例子:

some-command 2>&1 > command.log
some-command > command.log 2>&1

提问:这两条命令有什么区别?

很多对 Bash 不熟悉的同学看到了以后立刻说:“我知道我知道!第一条命令是把 stderr 重定向到 stdout,然后把 stdout 重定向到 command.log,因此命令执行完之后所有输出的内容都在 command.log 里面。第二条命令是把 stdout 重定向到 command.log 里,然后把 stderr 重定向到 stdout 里,因此命令执行完后 command.log 里只有 stdout 的输出,stderr 的输出还在屏幕上。”

这个答案正确么?很遗憾,每个句子里面“因此”前面的部分是完全正确的,但“因此”后面的部分完全错误,根本原因还是因为,大家把“重定向”的意思理解错了。为了正确理解这个问题,我们还是来仔细解释一下概念吧。

先看第一个命令,我们先做 2>&1,原先 2 指向的是屏幕,1 指向的是屏幕,因此做完这个重定向以后,2 里的所有内容被重定向到 1,也就是 stderr 被重定向到屏幕上。

然后,我们做 > command.log,原先 1 指向的是屏幕,重定向之后,1 指向的变成了文件,因此做完这个重定向以后,1 里的所有内容被重定向到文件,也就是 stdout 被重定向到文件里。

总之,命令一重定向的结果是,stderr 被重定向到屏幕上,stdout 被重定向到文件里,命令执行完后,文件里仅仅有 stdout 的输出。

理解了第一个命令之后,再看第二个命令也就很好理解了。我们先做 > command.log,原先 1 指向的是屏幕,做完这个重定向以后,1 里的所有内容被重定向到 command.log,也就是 stdout 被重定向到文件里。

然后,我们做 2>&1,原先 2 指向的是屏幕,1 指向的是文件 command.log,注意,1 已经被重定向到文件里了,因此,重定向之后,2 指向的也变成了文件,也就是 stderr 也被重定向到文件里。

总之,命令二重定向的结果是,stdoutstderr 都被重定向到文件里,命令执行完后,文件里有 stdoutstderr 的全部输出。

看明白了么?重定向的过程其实很简单,但由于和直观感受不一致,往往导致初学者在这里犯很多错误。希望这篇文章能解决初学者在输出重定向方面的疑惑。