If you have Perl, I'd do something like this:
$ perl -pe 'if (/M104/) { $i++; if($i == 2) { $_ = "M104 S999\n" } } ' test.txt
M104 S200
M107
M104 S999
M110
M104 S275
I.e. if /M104/
matches, increment $i
, then check if $i
is equal to 2, and if so, replace the current line (including the trailing newline, \n
)
You could use s/^M104.*/.../
in the last part if you want to use a sed-like substitution there.
Perl has the sed-like -i[extension]
option for in-place changes with or without a backup file.
Or passing the key values through env vars (makes scripting easier):
n=2 repl="S999" perl -pe 'if (/M104/) { $i++; if($i == $ENV{n}) { $_ = "M104 " . $ENV{repl} . "\n" } } ' test.txt
(or if you like chaining more than nesting, something like perl -pe '/M104/ and $i++ and $i == 2 and $_ = "M104 S999\n" ' test.txt
.)
or in awk:
$ awk '/M104/ { i++; if (i == 2) $0 = "M104 S999"; } 1' test.txt
But there's no standard in-place option for awk.
awk
for this job.