我正在阅读重定向数据 /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
代表 stderr
和 1
代表 stdout
。因此,如果我这样阅读,看起来我正在创建一个 stderr
文件和重定向 stdout
对吗?
如果是这样的话,那是什么呢 &
在那个命令吗?
你是对的, 2
是 STDERR
, 1
是 STDOUT
。当你这样做 2>&1
你是说:“打印到 STDOUT
(1
)将会发生的事情 STDERR
(2
)“。之前,你说过你的 STDOUT
会去的 /dev/null
。因此,没有看到任何东西。在示例1和2中,您将获得输出消息,因为它正在打印到 STDERR
,因为常规重定向只重定向 STDOUT
。
当你进行重定向时,你不会创建一个 STDERR
,过程总是有一个 STDERR
和a STDOUT
什么时候创建它们。
考虑下面的代码,它将单词“stdout”打印到stdout,将单词“stderror”打印到stderror。
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
请注意,'&'运算符告诉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
没有产出?要真正理解这一点,我强烈建议您阅读本文 文件描述符表上的网页。假设你已经完成了阅读,我们就可以继续了。请注意,Bash从左到右处理;因此Bash看到了 >/dev/null
第一个(与...相同) 1>/dev/null
),并将文件描述符1设置为指向/ dev / null而不是stdout。完成此操作后,Bash向右移动并看到 2>&1
。这将设置文件描述符2 指向同一个文件 作为文件描述符1(而不是文件描述符1本身!!!!(见 指针上的这个资源 了解更多信息)。由于文件描述符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 - > stdout。如果确实如此,则将代码重定向到/ dev / null 2>&1 >/dev/null
会给指针链2 - > 1 - > / dev / null,因此代码不产生任何东西,与我们上面看到的相反。
最后,我注意到有一种更简单的方法可以做到这一点:
从第3.6.4节 这里,我们看到我们可以使用运算符 &>
重定向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文档, 文件描述符表的解释, 指针简介