tags:

views:

591

answers:

3

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?

A: 

When I have multiple line pattern matching and/or replacing, I use awk or perl instead of sed. This is because I am not an expert of sed and for me other tools are more cooperative on such problems.

mouviciel
Yeah, I think I might have to go this route. Tried everything I could to get a variable put in... Looks like, it's time to start learning awk/perl :).
Todd Partridge
A: 

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.

Paul Stephenson
I little more than I know at the moment :) (got to learn about registers still) but works very well. Unfortunately this disallows usage of a varible: sed -e ':a;N;$!ba;s/$1\n n/Noun\n/'Any thoughts on this?
Todd Partridge
Do you mean a $1 in the search part or in the replace part? I'm not sure what's meant to happen when you put it in the search part.
Paul Stephenson
Yeah, this is for the search part. Apparently the variable isn't being read correctly when put there for some reason.
Todd Partridge
+2  A: 

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.

Dennis Williamson
Not only great command but great answer! - well described with un-ambiguous naming. I read through this once only and understood the meaning. Thank you Dennis!Oh, and good catch on the typo. ;)Sorry can't vote up as I don't have the reputation yet
Todd Partridge