【问题标题】:How to print matched regex pattern using awk?如何使用 awk 打印匹配的正则表达式模式?
【发布时间】:2011-07-29 00:08:20
【问题描述】:

使用awk,我需要在文件中找到与正则表达式模式匹配的单词。

想打印与模式匹配的单词。

所以如果排队,我有:

xxx yyy zzz

和模式:

/yyy/

我只想得到:

yyy

编辑: 感谢kurumi,我设法写了这样的东西:

awk '{
        for(i=1; i<=NF; i++) {
                tmp=match($i, /[0-9]..?.?[^A-Za-z0-9]/)
                if(tmp) {
                        print $i
                }
        }
}' $1

这正是我所需要的 :) 非常感谢!

【问题讨论】:

  • @maxtaldykin 您能否将问题中的自我回答移到单独的答案中?
  • 你不需要做tmp=match($i, /regexp);if(tmp){},你应该可以做if(tmp ~ $i){},因为~的意思是“匹配正则表达式”。

标签: regex awk


【解决方案1】:
echo "abc123def" | awk '

function MATCH(haystack, needle, ltrim, rtrim)
{
if(ltrim == 0 && !length(ltrim))
  ltrim = 0;

if(rtrim == 0 && !length(rtrim))
  rtrim = 0;

return substr(haystack, match(haystack, needle) + ltrim, RLENGTH - ltrim - rtrim);
}
    
{
print $0 " - " MATCH($0, "123");             # 123
print $0 " - " MATCH($0, "[0-9]*d", 0, 1);   # 123
print $0 " - " MATCH($0, "1234");            # Nothing printed
}'

【讨论】:

    【解决方案2】:

    听起来您正在尝试模仿 GNU 的 grep -o 行为。这将做到这一点,前提是您只需要每行的第一个匹配项:

    awk 'match($0, /regex/) {
        print substr($0, RSTART, RLENGTH)
    }
    ' file
    

    这是一个示例,使用 GNU 的 awk 实现 ():

    awk 'match($0, /a.t/) {
        print substr($0, RSTART, RLENGTH)
    }
    ' /usr/share/dict/words | head
    act
    act
    act
    act
    aft
    ant
    apt
    art
    art
    art
    

    awk 手册中了解matchsubstrRSTARTRLENGTH

    之后,您可能希望扩展它以处理同一行上的多个匹配项。

    【讨论】:

    • 注:要回答最后一部分,所有需要的结构都在 kurumi's answer 和我自己的。
    • 很好的答案。只是我想在这里解释一下,因为我很懒。但这就是我使用 AWK 的原因!
    • 如果我想对匹配结果做一些事情,除了打印它?例如,我想将所有匹配项添加到数组中。
    • @evya2005:您可以简单地将呼叫 Ron print 替换为您需要的作业。
    • 它对我不起作用。仅打印工作。你能给我举个例子吗?
    【解决方案3】:

    如果您知道要查找的文本/模式(例如“yyy”)在哪一列,您只需检查该特定列以查看它是否匹配,然后打印出来。

    例如,给定一个包含以下内容的文件,(称为 asdf.txt

    xxx yyy zzz
    

    如果第二列与模式“yyy”匹配,则仅打印第二列,您可以执行以下操作:

    awk '$2 ~ /yyy/ {print $2}' asdf.txt
    

    请注意,这也将基本上匹配第二列中包含“yyy”的任何行,如下所示:

    xxx yyyz zzz
    xxx zyyyz
    

    【讨论】:

      【解决方案4】:

      题外话,这也可以使用 grep 来完成,如果有人正在寻找 grep 解决方案,只需在此处发布即可

      echo 'xxx yyy zzze ' | grep -oE 'yyy'
      

      【讨论】:

      • 即使使用正则表达式也能轻松获取它。正是我需要的。谢谢!
      • 这对我有用;我的情况是这样的: echo "web_port=8080,shutdown_port=8005" | grep -oE "web_port=[0-9]+" # 返回 8080
      【解决方案5】:

      如果您只对输入的最后一行感兴趣并且只希望找到一个匹配项(例如 shell 命令的摘要行的一部分),您也可以试试这个非常紧凑的代码,采用自 @987654321 @:

      $ echo "xxx yyy zzz" | awk '{match($0,"yyy",a)}END{print a[0]}'
      yyy
      

      或者更复杂的部分结果:

      $ echo "xxx=a yyy=b zzz=c" | awk '{match($0,"yyy=([^ ]+)",a)}END{print a[1]}'
      b
      

      警告:带三个参数的awkmatch()函数只存在于gawk中,而不存在于mawk

      这是另一个很好的解决方案,在grep 中使用lookbehind regex 而不是awk。此解决方案对您的安装要求较低:

      $ echo "xxx=a yyy=b zzz=c" | grep -Po '(?<=yyy=)[^ ]+'
      b
      

      【讨论】:

      • 为什么要加“tail -n1”?没有它应该可以正常工作,不是吗?
      • @ArthurAccioly 正确。我使用该术语从 ping 调用中提取平均往返时间,这就是它的来源。有趣的是花了 4 年才发现它;)
      【解决方案6】:

      在这种情况下使用 sed 也很优雅。示例(用匹配组“yyy”从行替换行):

      $ cat testfile
      xxx yyy zzz
      yyy xxx zzz
      $ cat testfile | sed -r 's#^.*(yyy).*$#\1#g'
      yyy
      yyy
      

      相关手册页:https://www.gnu.org/software/sed/manual/sed.html#Back_002dreferences-and-Subexpressions

      【讨论】:

      • 对于非 gnu sed 的解决方案是这样的:sed -n 's/^.*\(yyy\).*$/\1/gp' &lt; testfile
      • @GrigoryEntin - bsd sed 适用于原始答案。 POSIX 支持的扩展正则表达式开关是 -E,但在 FreeBSD 中,至少 -r 与 -E 相同(2010 年添加了 -r)。无论如何,尝试使用 -E(gnu sed 在 4.3 中添加了 -E)
      【解决方案7】:

      如果 Perl 是一个选项,你可以试试这个:

      perl -lne 'print $1 if /(regex)/' file
      

      要实现不区分大小写的匹配,请添加i 修饰符

      perl -lne 'print $1 if /(regex)/i' file
      

      在比赛后打印所有内容:

      perl -lne 'if ($found){print} else{if (/regex(.*)/){print $1; $found++}}' textfile
      

      打印比赛和比赛后的一切:

      perl -lne 'if ($found){print} else{if (/(regex.*)/){print $1; $found++}}' textfile
      

      【讨论】:

      • 这实际上完全符合我的要求。无法使用 awk 打印我的匹配项,但 perl 成功了。
      【解决方案8】:

      gawk 可以使用此作为操作来获取每一行的匹配部分:

      { if (match($0,/your regexp/,m)) print m[0] }
      

      匹配(字符串,正则表达式 [,数组]) 如果数组存在,则将其清除, 然后将数组的第零个元素设置为的整个部分 正则表达式匹配的字符串。如果 regexp 包含括号,则 数组的整数索引元素设置为包含 字符串匹配相应的括号子表达式。 http://www.gnu.org/software/gawk/manual/gawk.html#String-Functions

      【讨论】:

        【解决方案9】:

        这是最基本的

        awk '/pattern/{ print $0 }' file
        

        awk 使用// 搜索pattern,然后打印出该行,默认情况下称为记录,用$0 表示。至少阅读documentation

        如果您只想打印出匹配的单词。

        awk '{for(i=1;i<=NF;i++){ if($i=="yyy"){print $i} } }' file
        

        【讨论】:

        • 因为print 是默认操作:awk '/pattern/' file 就足够了。
        • @Johnsyweb,是的,我知道这个事实。对于像 marverix 这样的初学者来说,它意味着更直观。
        • 我不怀疑你的知识。但是,这些信息可能对其他找到此答案的人有用。
        • 注意:如果 (a) "yyy" 是一个正则表达式而不是一个直字符串,并且 (b) 如果“yyy”与记录中的整个字段不匹配。
        • 不会是$i=="yyy";对于正则表达式,它将是 $i ~ /yyy/
        猜你喜欢
        • 1970-01-01
        • 2011-07-24
        • 2014-09-15
        • 2022-10-17
        • 2015-02-24
        • 1970-01-01
        • 1970-01-01
        • 2017-04-13
        • 1970-01-01
        相关资源
        最近更新 更多