ChatGPT解决这个技术问题 Extra ChatGPT

Grep 只匹配第一场比赛并停止

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

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

返回:

Pulsanti Operietur
Pulsanti Operietur

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


T
Trevor Boyd Smith

-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

我认为它们不是必需的(显然 -r 除外),但它们不应该受到伤害(虽然我不会使用 -a
正是我需要的。我的模式在同一行上被发现了两次,因此 grep -m 1 返回了两个实例。 |head -1 解决了!
一旦找到第一个匹配项,head 是否会短路?
@Chris_Rands 确切的行为取决于您正在运行的外壳。 head 将在遇到第一行时立即退出。 grep 将在 head 退出后下次尝试写入时退出。有些 shell 会等到管道的所有元素完成,有些会在管道中的最后一个程序退出时导致整个管道关闭。
@3Qn,我不明白你的评论:first not first from result。此答案在任何文件中打印第一个匹配项并停止。你还期待什么?
V
Venkat Kotra

您可以将 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 消失时它仍然输出一些东西到管道。

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


我正在尝试采用此解决方案来搜索具有 xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1 的大量存档文件。但是,这不会在第一场比赛中终止。有什么建议吗?
grep--line-buffered 选项不会在不调用其他实用程序的情况下防止缓冲区开销吗?
c
cxw

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


所以你会说 ack 比 grep 快?我也很关心速度因素。
ack 可能比 grep 更快,具体取决于您要搜索的内容。请注意,ack 是关于搜索源代码的。如果您要搜索一般文件,那么它就不那么擅长了,至少在 ack 1.x 中是这样。去阅读 ack 看看它是否适合你的需要。
我已经使用 Ack 很长一段时间了,但最近切换到 The silver searcher,我发现它的 Ack 速度更快
我相信这应该是唯一的答案,因为 OP 说他希望用 grep 完成,但另一个答案使用 head(当然都是工作)但是有一些嵌入式/自创环境,其中 grep 很常见,tail/头不是。
值得一提的是,ag 可能很快,但它没有具有在这种情况下有用的 -1 选项
4
4b0

如果要在当前目录中出现特定单词时要打印整行和文件名,则可以使用以下命令。

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

K
Katie Byers

对于像我一样登陆这里的任何人,对于为什么 --max-count 在对 stdin 采取行动时似乎没有工作感到困惑......

TL;DR - --max-count n不会在找到 n 个匹配项后停止,它会在找到所有匹配项后停止n

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

尽管事实上,在 zsh 5.8 中,至少 man grep 以这种方式描述了该选项,但这是正确的:

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

更长的解释

就我而言,我试图仅获取相对路径的第一部分:

>  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) 告诉它使用“扩展的”正则表达式,即您习惯于大多数其他编程语言的正则表达式。 “扩展”和“基本”之间的区别并不大 - 只是您需要在正则表达式中转义哪些字符 - 但作为主要是 TS 和 Python 开发人员的人,我总是使用 -E 因为我从来没有这样考虑一下。 (专业提示:将别名 grep="grep -E" 添加到您的 .zshrc 中,您将永远不必再担心它!)

-o (--only-matching) 告诉它只打印匹配项,而不是找到匹配项的每一行。

-mn (--max-count n) 将其限制为搜索 n 行。 (如果你读到这里,你显然已经知道了!😛)


S
Sergio Abreu

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

$ ifconfing | grep -E -o -m 1 "^[a-z0-9]+"

说明:-E 表示扩展正则表达式,-o 只返回匹配项,-m 1 只看一行


Y
Yam Marcovic

单个衬里,使用 find

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

这将非常非常慢,因为 find 将为找到的每个文件生成 grep 副本。 grep -r 的工作速度要快得多 - 它只有一个副本可以进行目录遍历。
真的;尽管可以将 find 自定义为仅对过滤后的结果进行操作,这可以使操作比包罗万象的 grep 快得多。取决于上下文。