How to replace only last match in a line with sed?
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:
-
Buggy behavior if word boundaries is used inside a group with quanitifiers - for example:
echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
fails - Greedy vs. Reluctant vs. Possessive Quantifiers
- Reference - What does this regex mean?
- sed manual: Back-references and Subexpressions
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
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, 2022Comments
-
Jan Warchoł almost 2 years
With
sed
, I can replace the first match in a line usingsed '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 almost 3 yearsThere is nothing GNU-specific here; this should work with any
sed
.