私はawkがラインブロックの先頭に移動し、ブロックの一番下に達した後に再処理を開始し、最後のラインを処理したいと思います。
デフォルトでは、テキストブロック
<START of block>
Hi
How
Are
You
<END of block>
「You」がブロックの最後の行であることを確認し、ブロックを印刷し、それ以外の場合は印刷しないようにします。私のファイルには異なる値を持つ複数のテキストブロックがあります。
処理を開始するために「line」変数に格納されている特定の行に移動するようにawkを取得できれば、私の目的は解決されます。
答え1
もし<START of block>
私は正しく理解しています<END of block>
。それとも含めませんか?)<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」と一致する行で終わるブロックのみを印刷します。つまり、1つだけを印刷するのではなく、一致するすべてのブロックを印刷します。
答え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>