Freebsd – BSD sed: Replace only the Nth occurrence of a pattern

bsdfreebsdregular expressionsedtext processing

Using BSD sed;

How can I perform the following substitution?:

Before:

hello hello hello
hello hello hello

After:

hello world hello
hello hello hello

In other words; how can I replace only the Nth occurence of a pattern?
(Or in this case; the 2nd occurrence of a pattern?)

Best Answer

With any POSIX sed:

$ sed -e'/hello/{' -e:1 -e'$!N;s/hello/world/2;t2' -eb1 -e\} -e:2 -en\;b2 <file
hello world hello
hello hello hello
  • After the first match /hello/, we run into a loop.

  • Inside loop :1, we read each Next line to the pattern space, doing substitute command for 2nd occurrence only. We test if the substitution success or not. If yes, we run into loop :2, else repeat the loop with b1.

  • Inside loop :2, we just print remain lines till the end of file.

Note that this approach will store all things between two hello in pattern space. It will be a problem with huge files, when the first and the second are far from each other.

Related Question