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


23

考虑以下输入文件:

1
2
3
4

跑步

{ grep -q 2; cat; } < infile

什么都不打印。我希望它能打印

3
4

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

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

为什么第一个命令不打印预期的输出?
这是一个可搜索的输入文件,符合OPTIONS下的标准

-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很重要(尽管Kusalananda刚刚确认在OpenBSD上也是如此)


如果有人想知道的,OpenBSD grepFreeGrep的分支。
库萨兰达

Answers:


37

grep 确实会提前停止,但是会缓冲其输入,因此您的测试太短了(是的,我知道我的测试是不完善的,因为它不可搜索):

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

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

seq 1 6775 | wc

输出

   6775    6775   32768

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

搜索多个文件时

由于部分读取单个文件,因此不会对性能提高抱有任何期望。


2

显然这是由于缓冲grep确实可以加快速度。有些工具专门用于读取要求的字符,而不再读取。其中之一是expect

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

我没有尝试进行此操作的系统,但我相信expect它将吃光所有内容,直到遇到预期的字符串(2),然后终止,将其余输入留给cat


1

您将sed和grep混淆了。

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

默认情况下,grep命令运行以输出所有匹配的行-但-q选项说不输出任何内容到stdout。因此,如果输入包含“ 2”,则其退出值为SUCCESS,否则为FAILURE。这些是什么取决于您的操作系统和外壳。因此,通常您可以通过检查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


6
您的答案是对的通用用法有用的信息,grep但是这个问题是在询问一些更微妙和深奥的东西。您似乎太快地阅读了该问题,无法理解所查询的实际行为。同样,GNU 在与配合使用时也grep 确实会停止搜索-q(如POSIX规范中的引用所允许):GNU grep的手册页指出它“如果发现任何匹配项,则立即以零状态退出”。FWIW,我已经编辑了您的问题,以显示如何格式化以后的帖子。欢迎堆栈交换
安东尼G-莫妮卡的正义

也就是说,@ user212377的答案是正确的:在这种情况下grep,将询问文件中是否存在“ 2”,仅此而已。它的行为尽如人意,sed并消耗了该点之前的记录,其余部分则留作进一步处理。它一直读取直到知道存在'2'或没有'2',然后关闭文件并返回结果。
基思·戴维斯

grep实际上,如果文件中不存在搜索字符串,则仅“消耗整个文件”(忽略缓冲注意事项)(只有通过检查整个文件才能证明)。除此之外,文件读取停止,文件关闭并返回SUCCESS。
基思·戴维斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.