Skip to main content
4 of 4
added 54 characters in body
Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k

With GNU sed (for the 0 address¹):

$ sed '0,/^line 1$/b; /^line 1$/,$ s/^line 3$/replaced/' < file
line 1
line 2
line 3
line 1
line 2
replaced
line 1
line 2
replaced

We branch out for the first 0,/^line 1/ range, which means the second /^line 1$/,$ only sees its starting line when reaching the second occurrence of line 1.

With awk, it's easier to spot the nth occurrence of line 1:

awk '$0 == "line 1" && ++n == 2, eof {if ($0 == "line 3") $0 = "replaced"}; 1'

(here eof is just any other uninitialised variable, so which yields false to signify that that first, last range has no end; same as just using 0 literally though more legible; similarly, we could use !skip instead of 1 to signify true for the current record to be printed but using 1 is idiomatic enough that it should be recognised by all awk users and a more legible alternative would rather be {print}).


¹ and since we assume GNU sed, we can also add ;more commands after the b one, which is not standard either. We'd need another -e 'more commands' with other seds.

Stéphane Chazelas
  • 584.6k
  • 96
  • 1.1k
  • 1.7k