如何使用 awk 打印匹配的正则表达式模式?

Posted

技术标签:

【中文标题】如何使用 awk 打印匹配的正则表达式模式?【英文标题】:How to print matched regex pattern using 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),因为~的意思是“匹配正则表达式”。 【参考方案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 实现 (gawk):

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)ENDprint a[0]'
yyy

或者更复杂的部分结果:

$ echo "xxx=a yyy=b zzz=c" | awk 'match($0,"yyy=([^ ]+)",a)ENDprint 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 elseif (/regex(.*)/)print $1; $found++' textfile

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

perl -lne 'if ($found)print elseif (/(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/

以上是关于如何使用 awk 打印匹配的正则表达式模式?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 awk 命令在匹配正则表达式之前和之后打印 5 行

awk-模式匹配

Linux AWK学习

如何使用 sed、awk 或 gawk 仅打印匹配的内容?

使用awk / grep / sed / bash / vim进行正则表达式匹配和打印

linux 下的 正则表达式(awk,sed,awk)学习