什么不起作用:
你引用最后一条命令的原因:
cmd 1>/dev/null 2>&1 | grep pattern
不起作用,源于对重定向工作顺序的混淆。您希望在每个输出上将最后引用的重定向应用于它之前的重定向,以便输出原始标准输出文件描述符 (1) 将转到 /dev/null,而输出到标准错误文件描述符 (2) 将转到原始标准输出。
但是,这不是 shell 重定向的工作方式。每次重定向都会导致文件描述符被“重新映射”,方法是关闭“源”并按顺序将“目标”复制到其中(参见dup(2) 和close(2) 的man 页)。这意味着在您的命令中,标准输出首先被替换为/dev/null,然后标准错误被替换为标准输出,已经是/dev/null。
什么有效:
因此,要获得预期的效果,您只需反转重定向即可。然后你会有标准错误转到标准输出,原来的标准输出到/dev/null:
cmd 2>&1 >/dev/null | grep pattern
(注意>之前的1是不必要的 - 用于输出重定向标准输出是默认的)
附录:Charlie 提到重定向到&- 以关闭文件描述符。如果使用支持该扩展的交互式外壳(bash 和其他一些实现,但不是全部,它是 not standard),您也可以这样做:
cmd 2>&1 >&- | grep pattern
这可能会更好 - 它可以节省一些时间,因为当命令尝试写入标准输出时,对 write 的调用可能会立即失败,而无需等待上下文切换到内核和驱动程序处理 /dev/null (取决于系统调用的实现——有些可能会在libc 函数中捕捉到这一点,有些还可能对/dev/null 进行特殊处理)。如果有很多值得的输出,并且输入速度更快。
这主要是可行的,因为大多数程序不关心它们是否无法写入标准输出(谁真正检查printf 的返回值?)并且不会介意标准输出已关闭。但是如果write 失败,一些程序可以通过失败代码退出——通常是阻塞处理器,程序使用一些仔细的库进行 I/O 或记录到标准输出。因此,如果它不起作用,请记住这是一个可能的原因并尝试 /dev/null。