Grep只有第一场比赛和停止

我正在使用grep和以下参数递归地搜索一个目录,希望只返回第一个匹配。不幸的是,它返回了不止一个——上次我查看时,实际上是两个。我似乎有太多的争论,尤其是没有得到预期的结果。: - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

返回:

Pulsanti Operietur
Pulsanti Operietur

也许grep不是最好的方法?你来告诉我,非常感谢。

670003 次浏览

-m 1表示返回任何给定文件中的第一个匹配项。但它仍将继续在其他文件中搜索。此外,如果在同一行中有两个或多个匹配,则将全部显示。

你可以使用head -1来解决这个问题:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

每个grep选项的解释:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively

我的类似grep-a的程序ack有一个-1选项,它在任何地方找到的第一个匹配处停止。它也支持@mvp所指的-m 1。我之所以把它放在那里,是因为如果我正在搜索一棵巨大的源代码树,以找到我知道只存在于一个文件中的某些东西,那么就没有必要找到它并必须按Ctrl-C。

使用find的单个内衬:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit

你可以将grep结果与stdbuf连接到head

注意,为了确保在第n次匹配后停止,你需要使用stdbuf来确保grep不会缓冲它的输出:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

只要head消耗1行,它就会终止,并且grep将接收SIGPIPE,因为在head消失时,它仍然会向管道输出一些内容。

这假设没有文件名包含换行符。

你可以使用下面的命令,如果你想打印整个行和文件名,如果特定的字出现在当前目录你正在搜索。

grep -m 1 -r "Not caching" * | head -1

阅读grep手册(man grep),这是查找第一个与扩展regexp匹配的最小命令。示例获取以太网名称,在我的笔记本电脑不是eth0 !

$ ifconfig | grep -E -o -m 1 "^[a-z0-9]+"
< p >解释: -E用于扩展regexp, -o只返回匹配项本身, -m 1只查找一个匹配

对于任何像我一样降落在这里的人来说,困惑于为什么--max-count在作用于stdin时似乎没有工作…

博士TL; - --max-count n在找到n匹配后停止,在找到所有匹配n后停止。

(而stdin,即使它只是一个字符串,也算作一行。)

这是正确的,尽管至少在zsh 5.8中,man grep是这样描述选项的:

-m num, --max-count=num
Stop reading the file after num matches.

更详细的解释

在我的例子中,我试图抓取相对路径的第一部分(下面的例子中的some):

>  echo "some/path/here" | grep -E -o -m 1 '[^\/]+'

当它把我还给我的时候,我很困惑

some
path
here

多亏了上面@harperville的评论,我终于明白了:这不是关于输出,而是关于输入

的确,当我尝试的时候

>  echo "some/path/here\nanother/path/there" | grep -E -o -m 1 '[^\/]+'

我得到了与上面相同的结果(即,在第二个例子中,只有\n之前的部分)。

笔记

对于那些不太熟悉grep的人:

  • -E (--extended-regexp)告诉它使用“扩展”;正则表达式,即您在大多数其他编程语言中所习惯的正则表达式。“扩展”与“扩展”的区别;和“;basic"不是很大——它只是关于你需要在正则表达式中转义哪些字符——但作为一个主要是TS和Python开发人员的人,我总是使用-E,因为这样我就不必考虑它。(提示:将alias grep="grep -E"添加到你的.zshrc,你就再也不用担心它了!)
  • -o (--only-matching)告诉它只打印匹配项,而不是打印找到匹配项的每一行。
  • -m n (--max-count n)限制它搜索n行。(如果你已经读到这里,你显然已经知道了!😛)