我希望 awk 转到行块的开头,以便在到达该块的底部并处理其最后一行后再次开始处理它。
基本上,如果文本块是
<START of block>
Hi
How
Are
You
<END of block>
我想要 awk 检查“You”是否是该块的最后一行,然后打印该块,否则不打印它。我的文件中有多个具有不同值的文本块。
如果我可以让 awk 转到存储在“line”变量中的特定行来开始处理,那么我的目的就得到了解决。
答案1
如果我理解正确:-您的输入有一个专用行表示“ <START of block>
”,另一个表示“ <END of block>
”,并且您想要打印该块(包括这两个标记?或不?)如果它们在之前的行中以“You”结尾” <END of block>
“?
然后:
awk -v regstart="<START of block>" -v regend="<END of block>" -v reglast="You" '
BEGIN { rem="we will remember a block between those regstart and regend markers, and only print it if the last line matches reglast"
remember=0; rem="by default we are not inside a block, so we do not remember lines until we match the regstart"
}
( $0 ~ regstart ) {
remember=1; nb=0;
}
( remember==1 ) {
line[++nb]=$0 ;
}
( $0 ~ regend ) {
remember=0; rem="we reached the end of block, we do not remember anymore the lines we see until next regstart"
if ( line[(nb-1)] ~ reglast ) {
## for(i=2;i<=(nb-1);i++) { rem="this version do NOT show the 2 marker lines"
for(i=1;i<=nb;i++) { rem="this version shows the 2 marker lines"
print line[i]
}
## print "" ; rem="uncomment this line if you want a separator lines between blocks"
}
}
'
注意1:我使用正则表达式来匹配开始、结束和最后一行,但您可以使用“==”来比较确切的字符串。
注2:打印部分:可以从2到nb-1,以不显示START(存储在行[1]中)和END(存储在行[nb]中)行。
注意3:上面的脚本愉快地处理每个块,并且只打印那些以匹配“reglast”的行结束的块。即它不仅打印一个,而且打印所有匹配的块。
答案2
awk
下面是一个较短的输入替代方案:
< infile awk -v RS='\n<END of block>' '$NF == "You" { print $0 RS }'
<START of block>
Hi
How
Are
You
<END of block>
<START of block>
thank
You
<END of block>
$NF
这里(根据RS
静态字符串的定义(记录分隔符)设置,使我们基于此分隔每个块)指示最后一行的值,因此如果它与Yes
字符串相等,则打印该块并也恢复回 RS。
输入文件:
<START of block>
Hi
How
Are
You
<END of block>
<START of block>
Hi
How
Are
not YOU
<END of block>
<START of block>
thank
You
<END of block>
<START of block>
welcome
to
Unix
<END of block>