Kyle_the_hacker
Kyle_the_hacker

Reputation: 1434

sed insert multiple lines before multiple lines pattern

I have the following very long file:

...
close unit 1
...
...
close unit 1
...
...
close unit 1

stop

I want to insert multiples lines before the last close unit 1 which is before stop. The file contains an undefined number of close unit 1.

I found a lot of other similar questions here and there, but the answers couldn't help me... For example I tried https://stackoverflow.com/a/8635732/1689664 but this didn't work...

Upvotes: 2

Views: 1192

Answers (3)

potong
potong

Reputation: 58410

This might work for you (GNU sed):

sed '/close unit 1/,$!b;/close unit 1/{x;/./p;x;h;d};H;$!d;x;i\line 1\nline 2\n...' file

Print every line before the first occurrence of close unit 1 as normal. Store collections of lines beginning with close unit 1 in the hold space and print the previous collection before storing the next. At the end of the file, the last collection will still be in the hold space, so insert the lines required and then print the last collection.

Upvotes: 0

devnull
devnull

Reputation: 123498

Using sed and tac:

$ tac inputfile | sed '/close unit 1/ {s/\(.*\)/\1\nLine3\nLine2\nLine1/; :loop; n; b loop}' | tac
...
close unit 1
...
...
close unit 1
...
...
Line1
Line2
Line3
close unit 1

stop

Note that you'd need to specify the input lines in the reverse order in the sed expression.

Upvotes: 2

choroba
choroba

Reputation: 241858

Perl solution:

perl -ne '  push @arr, $_;
            print shift @arr if @arr > 3;
            if ("stop\n" eq $_ and "close unit 1\n" eq $arr[0]) {
                print "\n\n";                                     # Inserted lines
            }
         }{ print @arr ' long-file > new-file

It keeps a sliding window of last 3 lines, if the last line in the window is stop and the first one is close unit 1, it prints the lines.

Another possibility is to use nl to number the lines, then grep lines containing close unit 1, getting the number of the last such a line and using it in a sed address:

nl -ba long-file \
    | grep -F 'close unit 1' \
    | tail -n1 \
    | ( read line junk
        sed -e $line's/^/\n\n/' long-file > new-file
      )

Upvotes: 1

Related Questions