cmd>如何? / dev / null 2>& 1工作?

时间:2013-06-08 02:29:17

标签: linux bash shell unix

我正在阅读将数据重定向到/dev/null,所以我尝试了一个简单的测试:

ping a.b.c  # which results in an address not found

如果我试试这个:

ping a.b.c > /dev/null # prints the same error message as the one above

但是,如果我这样做:

ping a.b.c > /dev/null 2>&1 # The error message is gone

最后一个解决方案是理想的解决方案,但是2>&1会发生什么?到目前为止,我的研究表明2代表stderr1代表stdout。因此,如果我以这种方式阅读,看起来我正在创建stderr文件并将stdout重定向到它?

如果是这种情况,该命令中的&会怎么做?

2 个答案:

答案 0 :(得分:12)

您是对的,2STDERR1STDOUT。当您执行2>&1时,您会说:“打印到STDOUT1STDERR2)”。在此之前,您说过STDOUT会转到/dev/null。因此,没有看到任何东西。在示例1和示例2中,您将获得输出消息,因为它正在打印到STDERR,因为常规重定向仅重定向STDOUT

当您进行重定向时,您没有创建STDERR,创建时,流程始终具有STDERRSTDOUT

答案 1 :(得分:0)

考虑下面的代码,它将单词“stdout”打印到stdout,将单词“stderror”输出到stderror。

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

请注意'&' operator告诉bash 2是文件描述符(指向stderr)而不是文件名。如果我们省略'&',此命令会将stdout打印到stdout,并创建一个名为“2”的文件并在那里写stderror

通过试验上面的代码,您可以准确地了解重定向运算符的工作原理。例如,通过将哪两个描述符1,2中的哪个文件重定向到/dev/null,以下两行代码将从stdout中删除所有内容,并从stderror中删除所有内容(打印剩余的内容)。

$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout

现在,我们接近问题的关键(用我的例子代替你的),为什么

(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1

没有产出?要真正理解这一点,我强烈建议您阅读此webpage on file descriptor tables。假设你已经完成了阅读,我们就可以继续了。请注意Bash从左到右处理;因此Bash首先看>/dev/null(与1>/dev/null相同),并将文件描述符1设置为指向/ dev / null而不是stdout。完成此操作后,Bash向右移动并看到2>&1。这将文件描述符2 设置为指向与文件描述符1相同的文件(而不是文件描述符1本身!!!!(有关更多信息,请参阅this resource on pointers)。由于文件描述符1指向/ dev / null,文件描述符2指向与文件描述符1相同的文件,文件描述符2现在也指向/ dev / null。因此两个文件描述符都指向/ dev / null,这就是为什么没有输出呈现。

要测试您是否真的理解这个概念,请在切换重定向顺序时尝试猜测输出:

(echo "stdout"; echo "stderror" >&2)  2>&1 >/dev/null
  

stderror

这里的推理是从左到右进行评估,Bash看到2>& 1,因此将文件描述符2设置为指向与文件描述符1相同的位置,即stdout。然后它设置文件描述符1(记住> / dev / null = 1> / dev / null)指向> / dev / null,从而删除通常发送到标准输出的所有内容。因此我们剩下的就是那些没有发送到子shell中的stdout(括号中的代码) - 即“stderror”。   值得注意的是,即使1只是指向stdout的指针,通过2>&1将指针2重定向到1也不会形成指针链2 - > 1 - >标准输出。如果是这样,由于将1重定向到/ dev / null,代码2>&1 >/dev/null将给出指针链2 - > 1 - > / dev / null,因此代码不产生任何东西,与我们上面看到的相反。

最后,我注意到有一种更简单的方法:

从第3.6.4节here开始,我们看到我们可以使用运算符&>来重定向stdout和stderr。因此,要将任何命令的stderr和stdout输出重定向到\dev\null(删除输出),我们只需键入 $ command &> /dev/null 或者在我的例子中:

$ (echo "stdout"; echo "stderror" >&2) &>/dev/null

关键要点:

  • 文件描述符的行为类似于指针(尽管文件描述符与文件指针不同)
  • 将文件描述符“a”重定向到指向文件“f”的文件描述符“b”,使文件描述符“a”指向与文件描述符b-文件“f”相同的位置。它不形成指针链a - > b - > ˚F
  • 由于上述原因,订单很重要,2>&1 >/dev/null是!= >/dev/null 2>&1。一个产生输出而另一个没产生!

最后看看这些优秀的资源:

Bash Documentation on RedirectionAn Explanation of File Descriptor TablesIntroduction to Pointers