3

Imagine a text file which contains random text and two unique markers

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

I want a sed/awk/perl/etc expression that moves the four interesting lines after the END marker to the position of the PREVIOUS BEGIN marker and also deletes both markers. Which should result in:

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

The two markers are always a pair and occur multiple times in the file. BEGIN marker always comes before END marker.

It doesn't have to be a oneliner, I would also use perl or python scripts.

I tried sed with:

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

...which did not work. The first DELETE_THIS_LINE_BEGIN marker was deleted (Nothing in Buffer for replacement) and the first DELETE_THIS_LINE_END marker was moved to the position of the second DELETE_THIS_LINE_BEGIN marker.

Any ideas?

6

awk:

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

Also, with awk, you can redefine the record separator:

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

produces the same result.

2

You will have to cache the lines that are between the markers and insert the cache after processing the 4 lines after the end-marker. In Python (tested with 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)
  • @sebweisgerber Of course. The original script has an extra line diff-ing output with a file with the result you wanted ;-) – Anthon Apr 25 '14 at 7:28
  • There's a small bug I noticed. The final buffer is not printed out, so content after the last marker is lost? @Anthon – sweisgerber.dev Apr 25 '14 at 7:48
  • I wrote a script in Python, that does nearly the same job, but uses not a fixed linecount, but a third marker: unix.stackexchange.com/questions/127273/… – sweisgerber.dev Apr 30 '14 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.