【问题标题】:How to grep for contents after pattern?如何grep模式后的内容?
【发布时间】:2012-05-08 16:03:18
【问题描述】:

给定一个文件,例如:

potato: 1234
apple: 5678
potato: 5432
grape: 4567
banana: 5432
sushi: 56789

我想对所有以potato: 开头的行进行 grep,但只对potato: 后面的数字进行管道传输。所以在上面的例子中,输出将是:

1234
5432

我该怎么做?

【问题讨论】:

    标签: linux grep


    【解决方案1】:
    grep 'potato:' file.txt | sed 's/^.*: //'
    

    grep 查找包含字符串 potato: 的任何行,然后,对于这些行中的每一行,sed 替换(s/// - 替换)从行首开始的任何字符(.*) (^) 直到最后一次出现序列 :(冒号后跟空格)和空字符串(s/...// - 用第二部分替换第一部分,它是空的)。

    grep 'potato:' file.txt | cut -d\   -f2
    

    对于包含potato: 的每一行,cut 将把该行拆分为多个由空格分隔的字段(-d\ - d = 分隔符,\ = 转义空格字符,类似于-d" " 会也有效)并打印每一行的第二个字段(-f2)。

    grep 'potato:' file.txt | awk '{print $2}'
    

    对于包含potato: 的每一行,awk 将打印默认由空格分隔的第二个字段 (print $2)。

    grep 'potato:' file.txt | perl -e 'for(<>){s/^.*: //;print}'
    

    所有包含potato: 的行都被发送到一个内联(-e)Perl 脚本,该脚本从stdin 中获取所有行,然后,对于这些行中的每一行,执行与第一个示例中相同的替换上面,然后打印出来。

    awk '{if(/potato:/) print $2}' < file.txt
    

    文件通过stdin 发送(&lt; file.txt 通过stdin 将文件的内容发送到左侧的命令)到awk 脚本,对于包含potato: 的每一行(@如果正则表达式 /potato:/ 与当前行匹配,则 987654358@ 返回 true),打印第二个字段,如上所述。

    perl -e 'for(<>){/potato:/ && s/^.*: // && print}' < file.txt
    

    文件通过stdin&lt; file.txt,见上文)发送到与上述类似的 Perl 脚本,但这次它还确保每一行都包含字符串 potato: (/potato:/是一个正则表达式,如果当前行包含 potato:,则匹配,如果是 (&amp;&amp;),则继续应用上述正则表达式并打印结果。

    【讨论】:

    • 不需要两个进程和一个管道。我会选择awk '$1 ~ /potato/ { print $2 }' file.txt
    • awk 更习惯用法是awk '/potato:/ {print $2}'
    • Perl 脚本可以受益于perl -pe
    【解决方案2】:
    sed -n 's/^potato:[[:space:]]*//p' file.txt
    

    可以将 Grep 视为受限 Sed,或将 Sed 视为广义 Grep。在这种情况下,Sed 是一款出色的轻量级工具,可以满足您的需求——当然,还有其他几种合理的方法可以做到这一点。

    【讨论】:

      【解决方案3】:

      或者使用正则表达式断言:grep -oP '(?&lt;=potato: ).*' file.txt

      【讨论】:

      • 我从上面接受的答案中尝试了一些单行,但我觉得这个答案更准确地解决了这个问题。
      • 一些解释:选项-o表示只打印该行的匹配部分。而-P 推断出与 Perl 兼容的正则表达式,恰好是 positive lookbehind 正则表达式 (?&lt;=string)
      • 注意:由于-P 选项,此解决方案仅与GNU grep 兼容,不适用于您可以找到的POSIX grep在 macOS 等环境中。
      【解决方案4】:

      这将在每次匹配后打印所有内容,仅在同一行:

      perl -lne 'print $1 if /^potato:\s*(.*)/' file.txt
      

      这将做同样的事情,除了它还将打印所有后续行:

      perl -lne 'if ($found){print} elsif (/^potato:\s*(.*)/){print $1; $found++}' file.txt
      

      使用这些命令行选项:

      • -n 循环输入文件的每一行
      • -l 在处理之前删除换行符,然后将它们添加回
      • -e执行perl代码

      【讨论】:

        【解决方案5】:

        您可以使用 grep,如其他答案所述。但您不需要 grep、awk、sed、perl、cut 或任何外部工具。你可以用纯 bash 来做到这一点。

        试试这个(分号可以让你把它全部放在一行上):

        $ while read line;
          do
            if [[ "${line%%:\ *}" == "potato" ]];
            then
              echo ${line##*:\ };
            fi;
          done< file.txt
        

        ## 告诉 bash 从前面删除 $line 中最长的 ":" 匹配项。

        $ while read line; do echo ${line##*:\ }; done< file.txt
        1234
        5678
        5432
        4567
        5432
        56789
        

        或者如果你想要键而不是值,%% 告诉 bash 从末尾删除 $line 中“:”的最长匹配项。

        $ while read line; do echo ${line%%:\ *}; done< file.txt
        potato
        apple
        potato
        grape
        banana
        sushi
        

        要拆分的子字符串是“:\”,因为空格字符必须用反斜杠转义。

        您可以在the linux documentation project 找到更多类似的内容。

        【讨论】:

        • while read 非常慢;只要您选择一个带有缓冲 I/O 的工具(即几乎本答案中提到的任何工具,以及许多其他工具),使用外部工具实际上会快得多。
        • 另外,你应该使用read -r,除非你非常特别地需要POSIX之前的一些相当讨厌的遗留行为。
        【解决方案6】:
        grep -Po 'potato:\s\K.*' file
        

        -P 使用 Perl 正则表达式

        -o 仅输出匹配项

        \s 匹配potato: 后面的空格

        \K 省略匹配

        .* 匹配其余字符串

        【讨论】:

        • 感谢正则表达式的解释。
        • 注意:由于-P 选项,此解决方案仅与GNU grep 兼容,不适用于您可以找到的POSIX grep在 macOS 等环境中。
        【解决方案7】:

        现代 BASH 支持正则表达式:

        while read -r line; do
          if [[ $line =~ ^potato:\ ([0-9]+) ]]; then
            echo "${BASH_REMATCH[1]}"
          fi
        done
        

        【讨论】:

          【解决方案8】:
          grep potato file | grep -o "[0-9].*"
          

          【讨论】:

            猜你喜欢
            • 2019-11-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-25
            • 2010-11-17
            • 2022-01-08
            • 1970-01-01
            相关资源
            最近更新 更多