Linux cmd>/开发/空2>&;1工作?
我正在阅读将数据重定向到Linux cmd>/开发/空2>&;1工作?,linux,bash,shell,unix,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 go
/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
)的内容。”。在此之前,您说过您的标准输出将转到/dev/null
。因此,什么也看不见。在示例1和2中,您得到输出消息是因为它被打印到STDERR
,作为常规重定向,它只重定向STDOUT
当您执行重定向时,您不是在创建STDERR
,进程在创建时总是有STDERR
和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) >/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
斯特德罗
这里的理由是,从左到右求值,Bash看到2>&1,因此将文件描述符2设置为指向与文件描述符1相同的位置,即stdout。然后设置文件描述符1(请记住>/dev/null=1>/dev/null)指向>/dev/null,从而删除通常发送到标准输出的所有内容。因此,我们只剩下子shell(括号中的代码)中没有发送到标准输出的内容,即“stderror”。
值得注意的是,尽管1只是一个指向标准输出的指针,但通过2>&1
将指针2重定向到1并不会形成指针链2->1->标准输出。如果是这样,则由于将1重定向到/dev/null,代码2>&1>/dev/null
将给出指针链2->1->/dev/null,从而得到与我们上面看到的相反,de不会产生任何结果
最后,我要指出,有一种更简单的方法:
从第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知道1
不是文件名,而是stderr
。顺便说一句,你不必使用
,ping a.b.c 2>/dev/null
或ping a.b.c&>/dev/null
应该这样做。@Joketster谢谢!如果1
不是文件名,那是什么?只是内存?你应该得到的“/dev/null:权限被拒绝",因为您试图将/dev/null
作为一个命令执行。它应该是/dev/null
,而不是/dev/null
@nkon,shell使用相同的约定。请注意,您可以编写:ping abc.example.com 2>/dev/null
,以便在不丢弃标准输出的情况下丢弃错误消息。@nkon如果需要,您实际上可以看到哪个文件描述符附加到进程。要做到这一点,请找到pid——例如,pgrep firefox
。然后ls-l/proc//fd
——注意,fd实际上在目录中表示为符号链接
$ (echo "stdout"; echo "stderror" >&2) &>/dev/null