$ sed ':again;$!N;$!b again; s/{[^}]*}//g' file
This is
that wants
anyway.
Explanation:
:again;$!N;$!b again;
This reads the whole file into the pattern space.
:again
is a label. N
reads in the next line. $!b again
branches back to the again
label on the condition that this is not the last line.
s/{[^}]*}//g
This removes all expressions in braces.
On Mac OSX, try:
sed -e ':again' -e N -e '$!b again' -e 's/{[^}]*}//g' file
Nested Braces
Let's take this as a test file with lots of nested braces:
a{b{c}d}e
1{2
}3{
}
5
Here is a modification to handle nested braces:
$ sed ':again;$!N;$!b again; :b; s/{[^{}]*}//g; t b' file2
ae
13
5
Explanation:
:again;$!N;$!b again
This is the same as before: it reads in the whole file.
:b
This defines a label b
.
s/{[^{}]*}//g
This removes text in braces as long as the text contains no inner braces.
t b
If the above substitute command resulted in a change, jump back to label b
. In this way, the substitute command is repeated until all brace-groups are removed.
As you are learning sed
, I'll take the time to add to @John1024's answer:
1) Please note that you are using \n
in the replacement string. This works in GNU sed
, but is not part of POSIX, so it will insert a backslash and an n
in many other sed
s (using \n
in the pattern is portable, btw).
Instead of this I suggest to do s/Network\([[:space:]]\)Administrator/System\1User/g
: The [[:space:]]
will match newline or whitespace, so you don't need two s
commands, but combine them in one. By surrounding it with \(...\)
you can refer to it in the replacement: The \1
will get replaced by whatever was matched in the first pair of \(\)
.
2) To properly match patterns over two lines, you should know the N;P;D
pattern:
sed '$!N;s/Network\([[:space:]]\)Administrator/System\1User/g;P;D'
The N
is always append the next line (except for the last line, that's why it's "addressed" with $!
(=if not last line; you should always consider to preceed N
with $!
to avoid accidentally ending the script). Then after the replacement the P
prints only the first line in the pattern space and the D
deletes this line and starts the next cycle with the remains of the pattern space (without reading the next line). This is probably what you originally intended.
Remember this pattern, you will often need it.
3) Another useful pattern for multiline editing, especially when more than two lines are involved: Hold space collecting, as I suggested to John:
sed 'H;1h;$!d;g;s/Network\([[:space:]]\)Administrator/System\1User/g'
I repeat it to explain it: H
appends each line to the hold space. As this would result in an extra newline before the first line, the first line needs to be moved instead of appended with 1h
. The following $!d
means "for all lines except the last one, delete the pattern space and start over". Thus, the rest of the script is only executed for the last line. At this point, the whole file is collected in the hold space (so don't use this for very large files!) and the g
moves it to the pattern space, so you can do all replacements at once like you can with the -z
option of GNU sed
.
This is another useful pattern I suggest to keep in mind.
Best Answer
This will do the job
/^ONE/,/TWO/
Look at the first line starting withONE
up toTWO
{/^ONE/!
do the following if my line does not start withONE
{/TWO/!d}}
do the following if my line does not start withTWO
anddelete
To summerize the above:
Find everything that starts with
ONE
up toTWO
. Another check is ran which means, find everything that don't match 'ONEand
TWO` and delete the rest.