How to delete 2 consecutive lines only when both patterns are matched

Solution for How to delete 2 consecutive lines only when both patterns are matched
is Given Below:

Let’s consider this simple file:

{
bla bla
bla bla bla
}
{
bla bla
bla bla bla
}
bla bla
bla bla bla

I need to remove only those consecutive lines:

}
{

The result should be:

{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

I tried the following:

sed -e '/^}$/,/^{$/d' file

Unfortunately, the last closing curly brace and remaining lines have been removed:

{
bla bla
bla bla bla
bla bla
bla bla bla

Any suggestion?

I’m open to any simple solution involving other tools such as awk/perl/… if necessary.

You may use this sed:

sed '/^}$/ { N; /n{$/ d; }' file

{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

To save changes inline:

sed -i.bak '/^}$/ { N; /n{$/ d; }' file

Alternatively this awk would also work:

awk '/^}$/ {p = $0; next} p != "" {if (/^{$/) {p=""; next} $0 = p ORS $0; p = ""} 1' file

{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

Perl solution:

perl -lne 'undef $prev, next if $prev eq "}" && $_ eq "{";
           print $prev if defined $prev;
           $prev = $_;
           END { print $prev if defined $prev}' -- file
  • -n reads the input line by line and runs the code for each line.
  • -l removes newlines from input and adds them to print.
  • We store the previous line in $prev. If the previous line was } and the current line is {, we forget the previous line and read the next line. Otherwise, we print the previous line if there was any (which means we don’t print an empty line after the forgotten line). Then we store the current line to $prev and repeat.
  • The END part is needed to print the last remembered line, if any.

With GNU sed for -z:

$ sed -z 's/}n{n//' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

With GNU awk for multi-char RS:

$ awk -v RS='}n{n' -v ORS= '1' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

$ sed '$!N;/^}n{$/d;P;D' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

This two line buffer will also work for other input as in the following test:

$ cat test
}
}
{
foo
}
$ sed '$!N;/^}n{$/d;P;D' test
}
foo
}

Also you may use this awk:

awk 'BEGIN{RS="";FS=OFS="n"}{print $1,$2,$3,$6,$7,$8,$9,$10}' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla

Or using for loop:


awk 'BEGIN{RS="";FS=OFS="n"}{
        for(i=1;i<=NF;i++) {
                if(i == 4 || i == 5) continue; print $i}
}' file
{
bla bla
bla bla bla
bla bla
bla bla bla
}
bla bla
bla bla bla