Here's a way to do it in sed
without slurping the whole file into memory:
- find the first occurrence of the pattern
- append the next line
N
to the pattern space
- attempt to replace the second occurrence of the pattern
- branch back and append another line if the match fails
Ta
The $q
quits the loop if the end of file is reached without a match.
So
sed '/Fred Flintstone/ {:a; $q; N; s//& someString/2; Ta;}' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
Although T
is a GNU extension, you can do the same in POSIX sed
using t; ba
Hmm... after thinking about this some more, it will actually append the new text to every other occurrence - not only the second. If you really need to use replace only the second occurrence, then the only way I can think to do it would be:
- address and replace the first instance with some unique string
- address and modify the new first instance
- address and replace the unique string with the original pattern
GNU sed
provides a trick to address the first instance of a pattern
0,/pattern/
So
sed -e '0,/Fred Flintstone/ s//Barney Rubble/' \
-e '0,/Fred Flintstone/ s//& someString/' \
-e '0,/Barney Rubble/ s//Fred Flintstone/
' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
If you don't mind using ed, then you can address the second instance more directly by going to the first line and then matching forward from one instance to the next:
ed -s File1 << \EOF
1;#
/Fred Flintstone/,/Fred Flintstone/ s//& someString/
,p
q
EOF
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
or as a one-liner
printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1
You can make the ed version in-place by replacing ,p
with w