简答:Command >filename 2>&1 或 Command &>filename
解释:
考虑以下代码,它将单词“stdout”打印到stdout,并将单词“stderror”打印到stderror。
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
请注意,'&' 运算符告诉 bash 2 是文件描述符(指向 stderr)而不是文件名。如果我们省略了 '&',此命令会将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
标准错误
这里的推理是,从左到右计算,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。如果确实如此,由于将 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 Redirection、An Explanation of File Descriptor Tables、Introduction to Pointers