我在 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
?或者任何pattern
s 出现故障?下面的代码处理这些情况(还删除未找到模式的行)。
查看样本输入的最后几行,以及样本输出最后几行中提取的模式。 (注意,我已从下面的示例中删除了空行):
输入示例:
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