【问题标题】:Grep only the first match and stopGrep 只匹配第一场比赛并停止
【发布时间】:2012-12-15 03:10:13
【问题描述】:

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

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

返回:

Pulsanti Operietur
Pulsanti Operietur

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

【问题讨论】:

    标签: grep


    【解决方案1】:

    -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。此答案在任何文件中打印第一个匹配项并停止。你还期待什么?
    【解决方案2】:

    我的类似 grep 的程序 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/head 不常用的工具。
    • 值得一提的是ag 可能很快,但它没有在这种情况下很有用的-1 选项
    【解决方案3】:

    单个衬里,使用find:

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

    【讨论】:

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

    您可以将 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 选项不会在不调用其他实用程序的情况下防止缓冲区开销吗?
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

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

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

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

      【讨论】:

        【解决方案7】:

        对于任何来到这里的人,就像我一样,困惑于为什么 --max-count 在对 stdin 采取行动时似乎不起作用......

        TL;DR - --max-count n 在找到 n 匹配项后会停止,它会在找到所有匹配项后停止n 行 em>。

        (还有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,因为那样我从来没有必须考虑一下。 (专业提示:将alias grep="grep -E" 添加到您的.zshrc,您就再也不用担心了!)
        • -o (--only-matching) 告诉它只打印匹配项,而不是找到匹配项的每一行。
        • -m n (--max-count n) 将其限制为搜索 n 行。 (如果你已经读到这里,那么你显然已经知道了!?)

        【讨论】:

          猜你喜欢
          • 2022-11-23
          • 2016-11-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多