为什么 grep 默认情况下不删除 find 命令的终端输出行?

为什么 grep 默认情况下不删除 find 命令的终端输出行?

我经常对这个简单的命令感到沮丧:

find / | fgrep somestuff.ext

当我不使用 时sudo,我会得到一行又一行的权限被拒绝 - 这很公平,但是为什么当 grep 从管道读取它时,这个输出没有被忽略?

为什么这种形式的输出直接发送到终端窗口而不是传递到管道中(我怀疑一定会发生这种情况)并随后被 grep 忽略,而 cat 生成的相同行(假设我有权限被拒绝的消息存储在文本中) file) 会正确地进入管道并被我的 grep 模式忽略吗?

我觉得 STDIN/STDOUT 过程中有一些我不理解的地方

答案1

权限被拒绝的消息不会发送到 stdout,find而是发送到 stderr。您可以将整个 stderr 重定向到位存储桶:

find 2>/dev/null | fgrep somestuff.ext

另外,要查找给定的文件,您不需要任何 grep:

find . -name somestuff.ext

您仍然可以应用2>/dev/null.

要仅抑制权限被拒绝的消息,您可以使用

2> >(grep -v 'Permission denied' >&2)

在bash中。

答案2

虽然 choroba 的好答案解决了您的问题,但您注意到的行为的原因是 bash 中的默认管道行为(我想在大多数 shell 中也是如此)。

如管道部分所述man bash

command 的标准输出通过管道连接到command2 的标准输入。此连接在命令指定的任何重定向之前执行(请参阅下面的重定向)。

这意味着stderrofcommand1默认情况下不会command2通过管道馈送,而是被驱动到您的 tty,即默认的 stderr 链接。

Bash 手册还说:

如果使用 |&,command 的标准错误除了其标准输出之外,还会通过管道连接到 command2 的标准输入;它是 2>&1 | 的简写。

因此,在您的情况下,如果您想通过管道传输到 grep 命令,默认情况下发送给/dev/stderr您的 find 命令错误需要使用以下两种形式之一:

find / |& fgrep somestuff.ext
find / 2>&1 | fgrep somestuff.ext

您的问题的标题也可以是“为什么管道忽略 stderr”。

答案是因为 bash 和 linux 就是这样默认的;stdout与 不同地对待stderr,以便用户能够以不同的方式记录/处理这两个输出。
例如,您可以通过管道将stdout命令 1 传送到stdin命令 2,同时您可以stderr使用 . 将命令 1 发送到日志文件2>errorlog.txt

实际上,当您运行没有指定任何重定向的命令时,例如

find /

它相当于

find / 1>/dev/stdout 2>/dev/stderr

最终解决为:

find / 1>/dev/tty1 2>/dev/tty1 #assuming that you are logged in tty1

可以通过单个验证ls

ls -all /dev/st*
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Nov 25 15:36 /dev/stdout -> /proc/self/fd/1

ls -all /proc/self/fd/2
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/2 -> /dev/tty1

ls -all /proc/self/fd/1
lrwx------ 1 root root 64 Nov 28 02:46 /proc/self/fd/1 -> /dev/tty1

如果出于任何原因您想要“加入”stdout命令stderr,那么您需要明确声明bash使用|&(对于管道)或2>&1(对于任何类型的输出重定向)的目的

相关内容