【问题标题】:Can grep show only words that match search pattern?grep 只能显示匹配搜索模式的单词吗?
【发布时间】:2010-12-05 12:37:14
【问题描述】:

有没有办法让 grep 从匹配搜索表达式的文件中输出“单词”?

如果我想在多个文件中找到“th”的所有实例,我可以这样做:

grep "th" *

但输出将类似于(粗体是我的);

some-text-file : the 猫坐在 the 垫子上 some-other-text-file : the quick brown fox 另一个文本文件:我希望 this 解释它彻底

我希望它使用相同的搜索输出的是:

the
the
the
this
thoroughly

这可以使用 grep 吗?还是使用其他工具组合?

【问题讨论】:

  • Dan Midwood 解决方案完美运行,值得称赞。
  • 有没有一种方法可以在不改变行的情况下打印那些匹配的单词。而是匹配的字符串应该保持在同一行?

标签: grep words


【解决方案1】:

只需awk,无需组合工具。

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly

【讨论】:

    【解决方案2】:

    试试grep -o

    grep -oh "\w*th\w*" *
    

    编辑:与菲尔的评论相匹配。

    来自the docs

    -h, --no-filename
        Suppress the prefixing of file names on output. This is the default
        when there is only  one  file  (or only standard input) to search.
    -o, --only-matching
        Print  only  the matched (non-empty) parts of a matching line,
        with each such part on a separate output line.
    

    【讨论】:

    • @user181548, grep -o 选项仅适用于 GNU grep。因此,如果您不使用 GNU grep,它可能不适合您。
    • @A-B-B 这取决于您是否要显示匹配文件的名称。我不确定它在什么条件下显示和不显示,但我知道当我在多个目录中使用 grep 时,它确实显示了所有匹配文件的完整文件路径,而使用 -h 它只显示匹配的单词没有任何关于它是哪个文件的说明。所以,为了匹配原始问题,我认为在某些情况下是必要的。
    • 我需要解释"\w*th\w*" * 的含义,所以我想我会发布。 \w 是 [_[:alnum:]],所以这基本上匹配任何包含 'th' 的“单词”(因为 \w 不包括空格)。引用部分后面的 * 是一个全局文件(即匹配此目录中的所有文件)
    • \w 通常不能移植到grep -E;为了获得适当的可移植性,请改用 POSIX 字符类名称 [[:alnum:]](如果您真的也想要下划线,则使用 [_[:alnum:]];如果您的平台有,请尝试 grep -P)。
    • @A-B-B 鉴于 OP 显示的所需输出,我会说 -h 是完全必要的.. ?
    【解决方案3】:

    您可以像这样将 grep 输出通过管道传输到 Perl:

    grep "th" * | perl -n -e'while(/(\w*th\w*)/g) {print "$1\n"}'
    

    【讨论】:

    • 不会给出正确的结果。此外,如果使用 Perl,则无需使用 grep。用 Perl 做所有事情。
    • 感谢您指出错误,ghostdog74。我已将其更改为打印行上的所有单词,而不仅仅是第一个。
    • 就像我说的,grep 不是必需的。 perl -n -e'while(/(\s+th\w*)/g) {打印 "$1\n"}' 文件
    • 由您决定。我只是说明一点。如果没有必要,请不要这样做。那个多余的“|”将花费您一个流程。
    • 在 Perl 5.10 或更高版本中: perl -nE '@a = /(regexp)/ig;说加入“\n”,@a'
    【解决方案4】:

    您可以将空格转换为换行符,然后 grep,例如:

    cat * | tr ' ' '\n' | grep th
    

    【讨论】:

    • 不需要猫。 tr ' ' '\n'
    • 这不起作用。输出仍然包含文件名和文件中包含匹配项的整行。无论如何,提供的其他解决方案之一有效。感谢您的意见。
    • @ghostdog74:好点,虽然如果你有多个文件,你需要使用 cat。 @Neil Baldwin:你确定你输入正确吗?当只有一个输入文件(本例中为标准输入)时,grep 不会打印文件名。
    • @Adam - 是的,对不起,亚当,它适用于一个文件,但不适用于多个文件。
    • @ghostdog74 如果慢的部分是因为tr,他可以先做grep,所以tr将只应用于匹配行:grep th filename | tr ' ' '\n' | grep th
    【解决方案5】:

    您也可以尝试 pcregrepgrep 中还有一个-w 选项,但在某些情况下它不能按预期工作。

    来自Wikipedia

    cat fruitlist.txt
    apple
    apples
    pineapple
    apple-
    apple-fruit
    fruit-apple
    
    grep -w apple fruitlist.txt
    apple
    apple-
    apple-fruit
    fruit-apple
    

    【讨论】:

      【解决方案6】:
      cat *-text-file | grep -Eio "th[a-z]+"
      

      【讨论】:

      【解决方案7】:

      我对 awk 难以记忆的语法不满意,但我喜欢使用一个实用程序来做到这一点的想法。

      似乎 ack(如果您使用 Ubuntu,则为 ack-grep)可以轻松做到这一点:

      # ack-grep -ho "\bth.*?\b" *
      
      the
      the
      the
      this
      thoroughly
      

      如果你省略 -h 标志,你会得到:

      # ack-grep -o "\bth.*?\b" *
      
      some-other-text-file
      1:the
      
      some-text-file
      1:the
      the
      
      yet-another-text-file
      1:this
      thoroughly
      

      作为奖励,您可以使用--output 标志来使用我发现的最简单的语法来执行更复杂的搜索:

      # echo "bug: 1, id: 5, time: 12/27/2010" > test-file
      # ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file
      
      1, 5, 12/27/2010
      

      【讨论】:

        【解决方案8】:
        $ grep -w
        

        摘自 grep 手册页:

        -w: 仅选择那些包含构成整个单词的匹配项的行。测试是匹配的子字符串必须要么在行首,要么前面有一个非单词组成字符。

        【讨论】:

        • 这仍然会打印包含匹配项的整行。它限制了实际匹配,以便 the 不再匹配,例如“这些”或“洗澡”。
        【解决方案9】:

        grep 命令只用于匹配和 perl

        grep -o -P 'th.*? ' filename
        

        【讨论】:

        • 只显示匹配组怎么样?
        • 这不起作用;它只会找到th,因为您要求使用最短的通配符重复。
        • @tripleee - 它不会有这个问题,因为正则表达式的末尾包含一个空格。但是,它会遗漏后面没有空格的单词,例如在行尾。
        【解决方案10】:

        我遇到了类似的问题,正在寻找 grep/pattern 正则表达式和“找到的匹配模式”作为输出。

        最后我使用了 egrep(grep -e 或 -G 上的相同正则表达式没有给我与 egrep 相同的结果)和选项 -o

        所以,我认为这可能类似于(我不是正则表达式大师):

        egrep -o "the*|this{1}|thoroughly{1}" filename
        

        【讨论】:

        • 应该删除无用的{1} 量词。或者如果你想保持一致,t{1}h{1}e{1} 等。
        • 可以同行打印吗?
        【解决方案11】:

        交叉分发安全答案(包括 windows minGW?)

        grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"
        

        如果您使用的是不包含 -o 选项的旧版本的 grep(如 2.4.2),请使用上述版本。否则使用下面更易于维护的版本。

        Linux 跨发行版安全答案

        grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'
        

        总结一下:-oh 输出与文件内容(而不是文件名)匹配的正则表达式,就像您期望正则表达式在 vim/etc 中的工作方式一样...您会使用什么词或正则表达式寻找然后,由你决定!只要您仍然使用 POSIX 而不是 perl 语法(请参阅下文)

        More from the manual for grep

        -o      Print each match, but only the match, not the entire line.
        -h      Never print filename headers (i.e. filenames) with output lines.
        -w      The expression is searched for as a word (as if surrounded by
                 `[[:<:]]' and `[[:>:]]';
        

        原来的答案并不适合所有人的原因

        \w 的用法因平台而异,因为它是扩展的“perl”语法。因此,那些仅限于使用 POSIX 字符类的 grep 安装使用 [[:alpha:]],而不是其 perl 等效的 \wSee the Wikipedia page on regular expression for more

        最终,无论 grep 的平台(是原始平台)如何,上面的 POSIX 答案都会更加可靠

        对于不带-o选项的grep的支持,第一个grep输出相关行,tr将空格分割成新行,最后的grep只过滤相应的行。

        (PS:我知道现在大多数平台都会为 \w....

        感谢@AdamRosenfield 回答的“-o”解决方法

        【讨论】:

        • -o 仅在 GNU grep 中工作怎么样(正如 ksinkar 在对已接受答案的评论中提到的那样)?
        • @Brilliand 嗯,我很难找到不支持'-o'的 linux 实现,如果我知道要检查哪个平台,我可以寻找解决方法。
        • @pico -o 选项在与 git 包 (minGW?) 一起安装的 windows grep 中不存在:"c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2
        • @BrucePeterson 我在 AdamRosenfield 解决方法中添加了 -o 的答案:帮我检查 windows git 是否包含 tr / sed 及其版本。所以我可以检查这个解决方法是否有效
        • @pico:对于 GIT:GNU sed 版本 4.2.1,tr (GNU textutils) 2.0
        【解决方案12】:

        要搜索以“icon-”开头的所有单词,以下命令可以完美运行。我在这里使用Ack,它与 grep 类似,但具有更好的选项和更好的格式。

        ack -oh --type=html "\w*icon-\w*" | sort | uniq
        

        【讨论】:

          【解决方案13】:

          这比你想象的要简单。试试这个:

          egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)
          
          egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)
          

          在哪里,

           egrep: Grep will work with extended regular expression.
           w    : Matches only word/words instead of substring.
           o    : Display only matched pattern instead of whole line.
           i    : If u want to ignore case sensitivity.
          

          【讨论】:

          • 这似乎并没有比 4 年前的现有答案添加任何内容。
          • @tripleee 我发现我的方法更好更简单,所以我发布了这个。
          【解决方案14】:

          ripgrep

          这里是使用ripgrep的例子:

          rg -o "(\w+)?th(\w+)?"
          

          它将匹配所有匹配th的单词。

          【讨论】:

          • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-22
          • 1970-01-01
          • 1970-01-01
          • 2011-04-23
          • 1970-01-01
          • 2015-10-12
          相关资源
          最近更新 更多