How to replace the last n occurences of string using sed

bashsed

I can replace the third occurrence of a string with:

sed 's/OLD/NEW/3'

or, with the GNU implementation of sed, all occurrences starting from the third with:

sed 's/OLD/NEW/3g'

But how do I replace the last 3 (or n) occurrences?

Best Answer

The simplest way to change the last three instances of a string that matches a specific pattern is to reverse each line of input and replace the reversed string:

$ echo 'this OLD is OLD OLD OLD!' | rev | sed -e 's/DLO/WEN/' -e 's/DLO/WEN/' -e 's/DLO/WEN/' | rev
this OLD is NEW NEW NEW!

There might be better ways of doing this if the specific format of the relevant lines is known. For example, in the test string I use above, we could simply have replaced OLD OLD OLD with NEW NEW NEW.

Note too that since regular expressions are applied in a left-to-right direction, replacing the reversed string may require a different pattern than the naive reversal of the original expression. As an example, consider that replacing the first two letters in abab, when reversed must replace the last two letters in baba.


Reversing a line can be done with sed like this, using @ as a pivot character to divide the string up into an unreversed and a reversed part:

:loop
s/^\([^@]\)\([^@]*\)@\{0,1\}\(.*\)/\2@\1\3/
t loop
s/@//
Related Question