为什么“grep -q”消耗整个输入文件?

为什么“grep -q”消耗整个输入文件?

考虑以下输入文件:

1
2
3
4

跑步

{ grep -q 2; cat; } < infile

不打印任何内容。我希望它能打印出来

3
4

如果我将其更改为,我可以获得预期的输出

{ sed -n 2q; cat; } < infile

为什么第一个命令没有打印预期的输出?
这是一个可搜索的输入文件,并且根据标准在下面选项

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

再往下,在应用程序使用(强调我的):

-q选项提供了一种轻松确定一组文件中是否存在模式(或字符串)的方法。当搜索多个文件时,它提供了性能改进(因为一旦找到第一个匹配就可以退出)[...]

现在,按照相同的标准(在介绍, 在下面输入文件

当标准实用程序读取可查找输入文件并在到达文件末尾之前无错误地终止时,实用程序应确保打开的文件描述中的文件偏移量正确定位在实用程序处理的最后一个字节之后[...]

tail -n +2 file
(sed -n 1q; cat) < file
...

仅当文件可查找时,第二个命令才与第一个命令等效。


为什么要grep -q消耗整个文件?


如果这gnu grep很重要的话(尽管善行难陀刚刚确认 OpenBSD 上也发生了同样的情况)

答案1

grep确实会提前停止,但它会缓冲其输入,因此您的测试太短(是的,我意识到我的测试是不完美的,因为它不可查找):

seq 1 10000 | (grep -q 2; cat)

在我的系统上从 6776 开始。那个匹配32KiB 缓冲区GNU grep 默认使用:

seq 1 6775 | wc

输出

   6775    6775   32768

请注意,POSIX 仅提到性能改进

当搜索多个文件时

由于部分读取单个文件,这并没有对性能改进产生任何期望。

答案2

这显然是由于缓冲确实grep可以加快速度。有些工具专门设计用于读取所请求的尽可能多的字符,而不是更多。其中之一是expect

{ expect -c "log_user 0; expect 2"; cat; } < infile

我没有一个系统可以尝试这个,但我相信expect会吃掉所有东西,直到遇到预期的字符串 ( 2),然后终止,将其余输入留给cat

答案3

您混淆了 sed 和 grep。

对于 sed 命令,如果在第二行,该选项表示安静地运行,则-2q表示退出当前迭代,因此您将获得第二行之后的所有行。-n

grep 命令默认运行以输出所有匹配的行 - 但该-q选项表示不向标准输出输出任何内容。因此,如果输入包含“2”,则退出值为“成功”,否则为“失败”。这些是什么取决于您的操作系统和 shell。因此,通常您会通过检查 grep 进程的退出值来判断一行是否匹配。这在您想知道输入是否包含某些值作为测试的管道中非常有用。例如

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

在这种情况下,我们实际上并不关心查看所有匹配的行,我们只关心是否至少存在一个。然后,进程report_crash_via_email/函数可能会关闭并重新打开文件,也可能不会。

如果您希望 grep 进程在找到“2”字符后停止 - 默认情况下不会,它会检查每一行以查看是否匹配 - 您需要告诉它这样做。其命令行开关是-m <value>。所以对于你的情况,grep -q -m1 2.

相关内容