用awk多次匹配多个模式的记录

时间:2012-02-28 10:37:46

标签: awk gawk

我正在尝试一次有效地匹配多个模式,这在原则上非常有效:

echo abcdef | awk \
'/abc/ {print "match abc"}
 /def/ {print "match def"}'

此外,我想匹配记录中的所有事件:

echo abcabc | awk \
'function findall(str, re) {
    while(match(str, re)) {
        print "match", re;
        str = substr(str, RSTART+RLENGTH)
    }
}
{
    findall($0, "abc");
}'

现在扩展上面的示例以匹配多个模式我最终会得到一系列findall调用:

findall($0, "abc");
...
findall($0, "def");

问题在于,使用许多不同的模式(> 100),这种方法的表现几乎不如第一个样本。这是有道理的,因为我想这个模式不会出现在同一个自动机中。

有没有办法加快一点速度?例如提供具有多种模式的“匹配”。我想我可以连接模式(abc | def),但是我会松开那些模式完全匹配的信息。

更新:应匹配每一次:

abcabc
123
abcxyz

因为输入数据会产生 2个匹配记录(给定标准分隔符)但 4匹配整个数据如果与模式“abc”和“xyz”一起使用。 这篇文章中的第一个样本至少报告 3个匹配,但未能检测到第一个记录中多次出现的“abc”

1 个答案:

答案 0 :(得分:2)

以这种方式做到这一点:

您将模式放在一个文件中,每个模式都放在一行中,而不是放在awk函数中。

e.g。

kent$  cat p.txt
abc
def
foo
xxx

然后你可以加载文件,让awk为你做匹配的工作。最后,只打印出与输入字符串匹配的模式:

    echo inputString|awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps)if(match($0,p))ps[p]++;}
END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -

当然,您可以替换" - "如果需要,请输入文件。

小测试:

kent$  echo "abcdefoobarblah"|awk 'NR==FNR{ps[$0]=0;next;}{for(p in ps)if(match($0,p))ps[p]++;}END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -
def matched
foo matched
abc matched

所以,模式" xxx"没有匹配。只打印出def,foo,abc。

注意脚本可以优化并缩短。例如,保存END {}块,在第一个for循环中执行打印。然而,它告诉你我的想法如何处理它。

编辑OP的评论

乔,我没有看到你问题中匹配时间的要求。但要实现并不困难。请参阅下面的测试,并附上示例文本:

kent$  echo "abcabcabcdefoobarblah"|
awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps){t=$0;ps[p]=gsub(p,"",t);}}
END{for(p in ps) if(ps[p]>0)print p" matched "ps[p]" time(s)"}' p.txt -

<强>输出:

def matched 1 time(s)
foo matched 1 time(s)
abc matched 3 time(s)