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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16995425/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:10:07  来源:igfitidea点击:

How does cmd > /dev/null 2>&1 work?

linuxbashshellunix

提问by hax0r_n_code

I'm reading up on redirecting data to /dev/nulland so I tried a simple test:

我正在阅读有关将数据重定向到的内容/dev/null,因此我尝试了一个简单的测试:

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

If I try this:

如果我试试这个:

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

However, if I do this:

但是,如果我这样做:

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

That last solution is the desired solution, but what is happening with this 2>&1? My research so far suggest that 2represents stderrand 1represents stdout. So if I read it that way, it looks like I'm creating a stderrfile and redirecting stdoutto it?

最后一个解决方案是所需的解决方案,但这是怎么回事2>&1?到目前为止,我的研究表明2代表stderr1代表stdout. 所以如果我这样读,看起来我正在创建一个stderr文件并重定向stdout到它?

If that is the case, what does the &in that command do?

如果是这种情况,&该命令中的 有什么作用?

采纳答案by msb

You are right, 2is STDERR, 1is STDOUT. When you do 2>&1you are saying: "print to STDOUT(1) the things that would go to STDERR(2)". And before that, you said your STDOUTwould go to /dev/null. Therefore, nothing is seen. In the examples 1 and 2 you get the output message because it is being printed to STDERR, as a regular redirection only redirects STDOUT.

你是对的,2STDERR1STDOUT。当你做2>&1你说:“打印到STDOUT1),这将去的东西STDERR2)”。在此之前,你说你STDOUT会去/dev/null。因此,什么也看不见。在示例 1 和 2 中,您会收到输出消息,因为它被打印到STDERR,因为常规重定向仅重定向STDOUT

And when you do the redirection, you are not creating a STDERR, the processes always have a STDERRand a STDOUTwhen they are created.

当您进行重定向时,您不是在创建 a STDERR,进程在创建时始终具有 aSTDERR和 a STDOUT

回答by Evan Rosica

Consider the following code which prints the word "stdout" to stdout and the word "stderror" to stderror.

考虑以下代码,它将单词“stdout”打印到 stdout,将单词“stderror”打印到 stderror。

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

Note that the '&' operator tells bash that 2 is a file descriptor (which points to the stderr) and not a file name. If we left out the '&', this command would print stdoutto stdout, and create a file named "2" and write stderrorthere.

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

By experimenting with the code above, you can see for yourself exactly how redirection operators work. For instance, by changing which file which of the two descriptors 1,2, is redirected to /dev/nullthe following two lines of code delete everything from the stdout, and everything from stderror respectively (printing what remains).

通过试验上面的代码,您可以亲眼看到重定向操作符是如何工作的。例如,通过更改两个描述符 1,2 中的哪个文件被重定向到/dev/null以下两行代码,分别删除 stdout 中的所有内容和 stderror 中的所有内容(打印剩余内容)。

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

Now, we approach the crux of the question (substituting my example for yours), why does

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

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

produce no output? To truly understand this, I highly recommend you read this webpage on file descriptor tables. Assuming you have done that reading, we can proceed. Note that Bash processes left to right; thus Bash sees >/dev/nullfirst (which is the same as 1>/dev/null), and sets the file descriptor 1 to point to /dev/null instead of the stdout. Having done this, Bash then moves rightwards and sees 2>&1. This sets the file descriptor 2 to point to the same fileas file descriptor 1 (and not to file descriptor 1 itself!!!! (see this resource on pointersfor more info) . Since file descriptor 1 points to /dev/null, and file descriptor 2 points to the same file as file descriptor 1, file descriptor 2 now also points to /dev/null. Thus both file descriptors point to /dev/null, and this is why no output is rendered.

没有产出?要真正理解这一点,我强烈建议您阅读有关文件描述符表的网页。假设您已完成阅读,我们可以继续。注意 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,这就是不呈现输出的原因。



To test if you really understand the concept, try to guess the output when we switch the redirection order:

为了测试你是否真的理解这个概念,试着猜测我们切换重定向顺序时的输出:

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

stderror

标准错误

The reasoning here is that evaluating from left to right, Bash sees 2>&1, and thus sets the file descriptor 2 to point to the same place as file descriptor 1, ie stdout. It then sets file descriptor 1 (remember that >/dev/null = 1>/dev/null) to point to >/dev/null, thus deleting everything which would usually be send to to the standard out. Thus all we are left with was that which was not send to stdout in the subshell (the code in the parentheses)- i.e. "stderror". The interesting thing to note there is that even though 1 is just a pointer to the stdout, redirecting pointer 2 to 1 via 2>&1does NOT form a chain of pointers 2 -> 1 -> stdout. If it did, as a result of redirecting 1 to /dev/null, the code 2>&1 >/dev/nullwould give the pointer chain 2 -> 1 -> /dev/null, and thus the code would generate nothing, in contrast to what we saw above.

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



Finally, I'd note that there is a simpler way to do this:

最后,我注意到有一种更简单的方法可以做到这一点:

From section 3.6.4 here, we see that we can use the operator &>to redirect both stdout and stderr. Thus, to redirect both the stderr and stdout output of any command to \dev\null(which deletes the output), we simply type $ command &> /dev/nullor in case of my example:

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

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


Key takeaways:

关键要点:

  • File descriptors behave like pointers (although file descriptors are not the same as file pointers)
  • Redirecting a file descriptor "a" to a file descriptor "b" which points to file "f", causes file descriptor "a" to point to the same place as file descriptor b - file "f". It DOES NOT form a chain of pointers a -> b -> f
  • Because of the above, order matters, 2>&1 >/dev/nullis != >/dev/null 2>&1. One generates output and the other does not!
  • 文件描述符的行为类似于指针(尽管文件描述符与文件指针不同)
  • 将文件描述符“a”重定向到指向文件“f”的文件描述符“b”,会导致文件描述符“a”指向与文件描述符b - 文件“f”相同的位置。它不会形成一个指针链 a -> b -> f
  • 由于上述原因,顺序很重要,2>&1 >/dev/null是 != >/dev/null 2>&1。一个生成输出,另一个不生成!


Finally have a look at these great resources:

最后看看这些很棒的资源:

Bash Documentation on Redirection, An Explanation of File Descriptor Tables, Introduction to Pointers

对重定向猛砸文档文件描述表的说明介绍指针