I can't think of a way to do this simply and elegantly in sed alone. It might be possible to do this with sed using write-only code, but I'd need a really good reason to write something like that. :-)
You still might be able to use sed
for this in conjunction with other tools:
$ tac test.txt | sed '/^Pattern 2$/,/^Pattern 1$/d' | tac
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
If your system doesn't have a tac
on it, you can create one with:
$ alias tac="awk '{L[i++]=\$0} END {for(j=i-1;j>=0;)print L[j--]}'"
or in keeping with the theme:
$ alias tac='sed '\''1!G;h;$!d'\'
That said, I'd do this in awk, like so:
$ awk '/Pattern 1/{printf "%s",b;b=""} {b=b $0 ORS} /Pattern 2/{b=""} END{printf "%s",b}' text.txt
Pattern 1
some text to keep
nice text here
Pattern 1
another text to keep
Or split out for easier reading/commenting:
awk '
/Pattern 1/ { # If we find the start pattern,
printf "%s",b # print the buffer (or nothing if it's empty)
b="" # and empty the buffer.
}
{ # Add the current line to a buffer, with the
b=b $0 ORS # correct output record separator.
}
/Pattern 2/ { # If we find our close pattern,
b="" # just empty the buffer.
}
END { # And at the end of the file,
printf "%s",b # print the buffer if we have one.
}' test.txt
This is roughly the same as hek2mgl's solution, but orders things a little more reasonably and uses ORS. :-)
Note that both of these solutions behave correctly only if Pattern 2
exists only once within the file. If you have multiple blocks, i.e. with both start and end patterns included, you'll need to work a little harder for this. If this is the case, please provide more detail in your question.