CDuv
CDuv

Reputation: 2260

How to add line before match within given line range/patterns using sed?

I want to do a basic sed-line insertion but withing a given line range.

Using given sample file sample.txt:

foo
tomato
apple
bar
START_MARKER
tomato
apple
kiwifruit
pineapple
strawberry

END_MARKER

apple
qux

I want to add a line (say "_____new_line_____") before any line between "START_MARKER" and "END_MARKER" that contains "apple". My sample would then become:

foo
tomato
apple
bar
START_MARKER
tomato
_____new_line_____
apple
kiwifruit
_____new_line_____
pineapple
strawberry

END_MARKER

apple
qux

I tried:

sed '/^START_MARKER$/,/^END_MARKER$/ /apple/i _____new_line_____' sample.txt

But I get:

sed: -e expression #1, char 33: unknown command: `/'

Also tried:

sed '/^START_MARKER$/,/^END_MARKER$/ {/apple/i _____new_line_____}' sample.txt

But I get:

sed: -e expression #1, char 0: unmatched `{'

If I wanted to add a "_____new_line_____" line before all line containing "apple" (not using START_MARKER and END_MARKER) the following would work:

sed '/apple/i _____new_line_____' sample.txt

I am missing something to chain/combine the /start/,/end/ pattern selection with my //i add-line-operation.

Upvotes: 2

Views: 926

Answers (3)

potong
potong

Reputation: 58430

This might work for you (GNU sed):

sed -e '/START/{:a;n;/apple/i\__newline__' -e '/END/!ba}' file

This inserts a line before any line containing apple between START and END or the end of the file.

To insert a line only between START and END before a line containing apple use:

sed -e ':a;/\n/{/^[^\n]*apple/i\__newline__' -e 'P;D};/START/{:b;N;/END/!bb;ba}' file

This gathers up the lines between START and END and only then inserts a line before the lines containing apple.

Upvotes: 0

beliz
beliz

Reputation: 402

You can use the following:

sed '/START_MARKER/,/END_MARKER/!b;/apple/ i_____new_line_____' sample.txt > out

where sed goes through every line and if the pattern 'apple' is in the range of START_MARKER and END_MARKER, it inserts '_____new_line_____' before 'apple' and if the pattern 'apple' is not in the range, then it does nothing.

If you don't direct the output to a file then it will print on the terminal screen.

Upvotes: 1

Sundeep
Sundeep

Reputation: 23667

With GNU sed

$ sed -e '/^START_MARKER$/,/^END_MARKER$/ { /apple/i _____new_line_____' -e '}' ip.txt
foo
tomato
apple
bar
START_MARKER
tomato
_____new_line_____
apple
kiwifruit
_____new_line_____
pineapple
strawberry

END_MARKER

apple
qux

Everything after a/c/i command is considered as the argument for that command. So, you need to separate them using newline or -e option as shown above. See https://www.gnu.org/software/sed/manual/sed.html#Commands-Requiring-a-newline for more details.


With other sed, this might work, but not sure as I can't test it:

sed '/^START_MARKER$/,/^END_MARKER$/ {
/apple/i\
_____new_line_____
}' ip.txt

Upvotes: 1

Related Questions