sed/awk/perl/etc: ファイル内の行を戻る

sed/awk/perl/etc: ファイル内の行を戻る

ランダムなテキストと2つのユニークなタグを含むテキストファイルを想像してください。

01 text text text
02 text text text
03 __DELETE_THIS_LINE_BEGIN__
04 text text text
05 text text text
06 text text text
07 text text text
08 __DELETE_THIS_LINE_END__
09 four
10 interesting
11 lines
12 follow
13 text text text
14 text text text
15 text text text
16 text text text
17 __DELETE_THIS_LINE_BEGIN__
18 text text text
19 text text text
20 text text text
21 text text text
22 __DELETE_THIS_LINE_END__
23 even
24 more
25 interesting
26 lines

ENDタグの後ろの興味深い4行を次に移動するsed / awk / perl / etc式が欲しいです。より早いBEGINは両方のマークを表示して削除します。結果は次のとおりです。

01 text text text
02 text text text
09 four
10 interesting
11 lines
12 follow
04 text text text
05 text text text
06 text text text
07 text text text
13 text text text
14 text text text
15 text text text
16 text text text
23 even
24 more
25 interesting
26 lines
18 text text text
19 text text text
20 text text text
21 text text text

これらの2つのタグは常にペアで、ファイルに複数回表示されます。 BEGINタグは常にENDタグの前にあります。

必ずしも1つのライナーである必要はなく、PerlやPythonスクリプトも使用します。

私はsedを試してみます:

sed -e '/__DELETE_THIS_LINE_END__/,+4 {H;d};/__DELETE_THIS_LINE_BEGIN__/ x' <source.txt> > <target.txt>

...これはうまくいきません。最初DELETE_THIS_LINE_BEGINマークが削除され(バッファに交換する項目がありません)、最初のDELETE_THIS_LINE_ENDマーカーが2番目の位置に移動しました。DELETE_THIS_LINE_BEGIN表示。

どんなアイデアがありますか?

答え1

奇妙な:

awk '
    /__DELETE_THIS_LINE_BEGIN__/ {keep=1; next} 
    /__DELETE_THIS_LINE_END__/   {keep=0; move=4; next}
    keep {saved[++s]=$0; next} 
    move-- == 0 {for (i=1; i<=s; i++) print saved[i]; delete saved; s=0}
    1
    END {for (i=1; i<=s; i++) print saved[i]}
' file 
01 text text text
02 text text text
09 four
10 interesting
11 lines
12 follow
04 text text text
05 text text text
06 text text text
07 text text text
13 text text text
14 text text text
15 text text text
16 text text text
23 even
24 more
25 interesting
26 lines
18 text text text
19 text text text
20 text text text
21 text text text

また、awk を使用すると、レコード区切り文字をオーバーライドできます。

awk -v RS='\n[0-9]+ __DELETE_THIS_LINE_(BEGIN|END)__\n' '
    NR%2 == 0 {saved=$0; next} 
    {
        n=split($0, lines, "\n")
        for (i=1; i<=4 && i<=n; i++) print lines[i]
        if (saved) print saved
        for (i=5; i<=n; i++) print lines[i]
    }
' file

同じ結果が生成されます。

答え2

タグ間の行をキャッシュして閉じるタグの後に4行を処理した後、キャッシュを挿入する必要があります。 Python(2.7でテスト):

#! /usr/bin/env python
buffer = []
in_block = False
max_interesting_line_nr = 4
begin_marker = "__DELETE_THIS_LINE_BEGIN__"
end_marker = "__DELETE_THIS_LINE_END__"
interesting_line = 0
with open('input') as inf:
    with open('output', 'w') as outf:
        for line in inf:
            if begin_marker in line:
                in_block = True
                continue
            if end_marker in line:
                assert in_block is True
                interesting_line = max_interesting_line_nr
                in_block = False
                continue
            if interesting_line:
                outf.write(line)
                interesting_line -= 1
                if interesting_line == 0:  # output gathered lines
                    for lbuf in buffer:
                        outf.write(lbuf)
                    buffer = []  # empty buffer 
                continue
            if in_block:
                buffer.append(line)  # gather lines
            else:
                outf.write(line)

関連情報