4

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?

Jan Warchoł
  • 933
  • 6
  • 21

3 Answers3

4

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:

Sundeep
  • 19,273
  • 2
  • 19
  • 42
4

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
fancyPants
  • 46,782
  • 31
  • 80
  • 91
4

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.

potong
  • 47,186
  • 6
  • 43
  • 72