使用 awk 匹配部分或全部模式

使用 awk 匹配部分或全部模式

我在 awk 多重模式匹配方面遇到了一个小问题,我无法弄清楚。我有以下 awk 行:

awk '/pat1/{v1=$4; next} /pat2/{v2=$5; next} /pat3/{v3=$6;next} /pat4/{v4=$5; print v1,"    ",v2,"    ",v3"    ",v4}' myfile.out

这给出了我想要的结果(每次匹配时将数学结果打印在一行上),因为它们全部匹配。如果其中一种模式不存在,则不会匹配任何内容。

因此,如果全部匹配,我就会得到我所期望的:

pat1    pat2    pat3    pat4
pat1    pat2    pat3    pat4
pat1    pat2    pat3    pat4
pat1    pat2    pat3    pat4
.
.
.

每行的值patX都不同!

有没有办法告诉 awk 寻找这些模式,如果它们看起来没有将这个地方留空?

因此,例如,如果在第一个实例中pat3尚未pat4出现在正在更新的文档中,那么我应该得到:

pat1    pat2    
pat1    pat2   pat3    ------> (here let's assume that pat3 has made an appearange)
pat1    pat2   pat3    pat4 ------> (here pat4 started to appear too)
pat1    pat2   pat3    pat4
pat1    pat2   pat3    pat4
.
.
.

这可以用 awk 完成吗?

编辑:这是我面临的两个示例场景。我的文件一开始是空的,然后填充了数据,我需要从中过滤一些模式。并非所有模式从一开始就出现。所以该文件将开始为:

some text here pat1
some more text here

some more text here pat2

some more text here and pat3


如果我使用上面的 awk 命令,它将给出空结果,因为pat4还不存在!随着时间的推移,它最终会出现。

some text here pat1
some more text here

some more text here pat2

some more text here and pat3

some more text here pat4

some text here pat1
some more text here

some more text here pat2

some more text here and pat3

some more text here pat4

some text here pat1
some more text here

some more text here pat2

some more text here and pat3

some more text here pat4

该命令的结果awk看起来符合预期:

pat1      pat2      pat3     pat4
pat1      pat2      pat3     pat4
pat1      pat2      pat3     pat4

然而,一开始我想得到的结果是:

pat1    pat2    pat3   

我希望现在更清楚了(我已经重写并测试了上面的 awk 命令以使其更简单)。

答案1

看来你需要类似的东西:

$ cat tst.awk
BEGIN { OFS="     " }

{ sub(/\r$/,"") }

( ($NF ~ /pat1/) && (state == 0) ) ||
( ($NF ~ /pat2/) && (state == 1) ) ||
( ($NF ~ /pat3/) && (state == 2) ) ||
( ($NF ~ /pat4/) && (state == 3) ) {
    v[++state] = $NF
}

state == 4 {
    print v[1], v[2], v[3], v[4]
    state = 0
}

$ awk -f tst.awk file
pat1     pat2     pat3     pat4
pat1     pat2     pat3     pat4
pat1     pat2     pat3     pat4

答案2

也许只需使用 END 子句来打印结果。

    awk '/pat1/{v1=$4; next} /pat2/{v2=$5; next} /pat3/{v3=$6; next} /pat4/{v4=$5;} END{ print v1,"    ",v2,"    ",v3"    ",v4 }' myfile.out

答案3

在尝试调整 @EdMorton 对我的问题的回答时,我从一位较早的人那里找到了我需要的信息线他提供了答案并设法完全解决了问题。这是我的解决方案:

awk '/pat1/{v1=$4; next}{v1="xxx"} /pat2/{v2=$5; next}{v2="xxx"} /pat3/{v3=$6;next}{v3="xxx"} /pat4/{v4=$5}{v4="xxx"} {print v1,"    ",v2,"    ",v3"    ",v4}' myfile.out

现在,当其中一种模式尚不存在时,我将xxx在其位置上找到一个。我可以xxx用单个空格字符或任何其他值替换。

感谢您的所有建议和帮助!

PS:我发现有时提供示例输入来解释问题并不那么容易。抱歉,如果这导致您感到沮丧!

答案4

使用 Raku(以前称为 Perl_6)

raku -e 'my @a; my @pat = <<pat1 pat2 pat3 pat4>>; for lines() { for @pat -> $i { @a.push( m[$i] // " __ " ) };}; .put unless $_ eq " __   __   __   __ " for @a.rotor(4);'

由于一个棘手的问题而用 Raku 回答:如果一行包含多个所需的怎么办pattern?或者任何patterns 出现故障?下面的代码处理这些情况(还删除未找到模式的行)。

查看样本输入的最后几行,以及样本输出最后几行中提取的模式。 (注意,我已从下面的示例中删除了空行):

输入示例:

some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some text here pat1
some more text here
some more text here pat2
some more text here and pat3
some more text here pat4
some more text here pat1 pat2
some more text here pat1 pat2 pat3 pat4

示例输出:

pat1  __   __   __ 
 __  pat2  __   __ 
 __   __  pat3  __ 
pat1  __   __   __ 
 __  pat2  __   __ 
 __   __  pat3  __ 
 __   __   __  pat4
pat1  __   __   __ 
 __  pat2  __   __ 
 __   __  pat3  __ 
 __   __   __  pat4
pat1 pat2  __   __ 
pat1 pat2 pat3 pat4

注意:一个常见的情况是不是上面的代码处理的是在一行的多个副本中找到单个模式的情况。上面的代码没有计算出现次数的机制,它只会告诉您是否“看到”某个模式。下面的例子:

echo "text here pat2 pat2 pat2 pat4" | raku -e 'my @a; my @pat = <<pat1 pat2 pat3 pat4>>; for lines() { for @pat -> $i { @a.push( m[$i] // " __ " ) };}; .put unless $_ eq " __   __   __   __ " for @a.rotor(4);'

重复模式输出:

__  pat2  __  pat4

http://raku.org

相关内容