Expression in math term, I'd like to delete a region of [MarkA,MarkB). I.e., the deletion happens right when the keyword MarkA is encountered, all the way to keyword MarkB, but not including that line (the line including MarkB keyword is left untouched).
Is it possible to do so in sed?
Say my MarkA is ^3, and MarkB is 7,
$ seq 9 | sed '/^3/,/7/d'
1
2
8
9It will get my 7 deleted but I want to preserve it.
To be more precise, I can accurately locate MarkA (e.g. ^3), but I want to delete up to the first MarkB. I.e.,
seq 19 | sed '/^3/,/7/d'is what I'm looking for if the 7 line is not deleted.
2 Answers
Using sed
This deletes the range up to but not including the last line in the range:
$ seq 9 | sed '/^3/,/7/{/7/p;d}'
1
2
7
8
9As before, /^3/,/7/ selects the whole range, inclusive of /7/. And, as before, that range gets deleted with the d command. However, before we delete, we check to see if the line contains /7/ and, in that case, we print it with the p command.
Using awk
awk offers much flexibility. Here, we use a variable f as a flag to decide if lines should be printed:
$ seq 9 | awk '/^3/{f=1} /7/{f=0} !f'
1
2
7
8
9 You could use sed's predecessor, ed, if you have the data in a file:
seq 9 > data
printf '%s\n' '/^3/,/7/-1 d' 'wq' | ed -s data
cat data
1
2
7
8
9The command breaks down like this:
printf-- send two strings down the pipe; those two strings have a newline appended to them so that they appear as commands toed. The two commands are:/^3/,/7/-1 d-- in the range /^3/ to one before /7/, delete the lineswq-- write the file back to disk and quit
ed -s data-- runedin silent mode, so that it does not report the number of bytes written at the end.
The core useful feature here is ed's ability to use addition or subtraction after the range regular expression. The (GNU) ed manpage describes it here:
A line address is constructed as follows:
...
Addresses can be followed by one or more address offsets, optionally separated by whitespace. Offsets are constructed as follows:
'+' or '-' followed by a number adds or subtracts the indicated number of lines to or from the address.
'+' or '-' not followed by a number adds or subtracts 1 to or from the address.
A number adds the indicated number of lines to the address.