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?

Todd Partridge 'Gen2ly'
  • 2,258
  • 2
  • 19
  • 18
  • 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 Oct 16 '09 at 09:35
  • 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 'Gen2ly' Oct 16 '09 at 21:56

3 Answers3

5

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
  • 346,391
  • 90
  • 374
  • 439
  • 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 'Gen2ly' Oct 18 '09 at 09:47
1

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.

Community
  • 1
  • 1
Paul Stephenson
  • 67,682
  • 9
  • 49
  • 51
  • 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 'Gen2ly' Oct 16 '09 at 11:30
  • 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 Oct 16 '09 at 13:13
  • Yeah, this is for the search part. Apparently the variable isn't being read correctly when put there for some reason. – Todd Partridge 'Gen2ly' Oct 16 '09 at 13:45
0

This might work for you:

sed '$!N;s/^fast\n\s*n :/Noun\n :/;P;D' file
...
Noun
 : abstaining from food
potong
  • 55,640
  • 6
  • 51
  • 83