How to replace only last match in a line with sed?

10,816

Solution 1

Copy pasting from something I've posted elsewhere:

$ # replacing last occurrence
$ # can also use sed -E 's/:([^:]*)$/-\1/'
$ echo 'foo:123:bar:baz' | sed -E 's/(.*):/\1-/'
foo:123:bar-baz
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):/\1-/'
456:foo:123:bar:789-baz
$ echo 'foo and bar and baz land good' | sed -E 's/(.*)and/\1XYZ/'
foo and bar and baz lXYZ good
$ # use word boundaries as necessary - GNU sed
$ echo 'foo and bar and baz land good' | sed -E 's/(.*)\band\b/\1XYZ/'
foo and bar XYZ baz land good

$ # replacing last but one
$ echo 'foo:123:bar:baz' | sed -E 's/(.*):(.*:)/\1-\2/'
foo:123-bar:baz
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):(.*:)/\1-\2/'
456:foo:123:bar-789:baz

$ # replacing last but two
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):((.*:){2})/\1-\2/'
456:foo:123-bar:789:baz
$ # replacing last but three
$ echo '456:foo:123:bar:789:baz' | sed -E 's/(.*):((.*:){3})/\1-\2/'
456:foo-123:bar:789:baz

Further Reading:

Solution 2

This might work for you (GNU sed):

sed 's/\(.*\)pattern/\1replacement/' file

Use greed to swallow up the pattern space and then regexp engine will step back through the line and find the first match i.e. the last match.

Solution 3

A fun way to do this, is to use rev to reverse the characters of each line and write your sed replacement backwards.

rev input_file | sed 's/nrettap/tnemecalper/' | rev
Share:
10,816
Jan Warchoł
Author by

Jan Warchoł

I'm a DevOps engineer interested in automation, lightweight processes, and maximizing the amount of work not done. I prefer Python over Ruby, and I'm an expert on Git version control. I'm also a music engraver. Productivity tools are my hobby, and I enjoy sharing my code on GitHub in the spirit of Free Software.

Updated on July 03, 2022

Comments

  • Jan Warchoł
    Jan Warchoł almost 2 years

    With sed, I can replace the first match in a line using

    sed 's/pattern/replacement/'
    

    And all matches using

    sed 's/pattern/replacement/g'
    

    How do I replace only the last match, regardless of how many matches there are before it?

  • tripleee
    tripleee almost 3 years
    There is nothing GNU-specific here; this should work with any sed.