Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed: Find pattern over two lines, not replace after that pattern

Tags:

linux

sed

Wow, this one has really got me. Gonna need some tricky sed skill here I think. Here is the output value of command text I'm trying to replace:

...
fast
     n : abstaining from food

The value I'd like to replace it with, is:

...
Noun
 : abstaining from food

This turns out to be tricker that I thought. Because 'fast' is listed a number of times and because it is listed in other places at the beginning of the line. So I came up with this to define the range:

sed '/fast/,/^     n : / s/fast/Noun/'

Which I thought would do, but... Unfortunately, this doesn't end the replacement and the rest of the output following this match are replaced with Noun. How to get sed to stop replacement after the match? Even better, can I find a two line pattern match and replace it?

like image 945
Todd Partridge 'Gen2ly' Avatar asked Jun 28 '26 01:06

Todd Partridge 'Gen2ly'


2 Answers

Try this:

sed "h; :b; \$b ; N; /^${1}\n     n/ {h;x;s//Noun\n/; bb}; \$b ; P; D"

Unfortunately, Paul's answer reads the whole file in which makes any additional processing you might want to do difficult. This version reads the lines in pairs.

By enclosing the sed script in double quotes instead of single quotes, you can include shell variables such as positional parameters. I would recommend surrounding them with curly braces so they are set apart from the adjacent characters. When using double quotes, you'll have to be careful of the shell wanting to do its various expansions. In this example, I've escaped the dollar signs that signify the last line of the input file for the branch commands. Otherwise the shell will try to substitute the value of a variable $b which is likely to be null thus making sed unhappy.

Another technique would be to use single quotes and close and open them each time you have a shell variable:

sed 'h; :b; $b ; N; /^'${1}'\n     n/ {h;x;s//Noun\n/; bb}; $b ; P; D'
#   ↑open        close↑    ↑open                                close↑

I'm assuming that the "[/code]" in your expected result is a typo. Let me know if it's not.

like image 68
Dennis Williamson Avatar answered Jun 29 '26 15:06

Dennis Williamson


This seems to do what you want:

sed -e ':a;N;$!ba;s/fast\n     n/Noun\n/'

I essentially stole the answer from here.

like image 38
Paul Stephenson Avatar answered Jun 29 '26 15:06

Paul Stephenson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!