10

I would like to sed only the last match pattern of a text file.

input file:

boy
boy
girl
boy

output file:

boy
boy
girl
boys
Birei
  • 35,723
  • 2
  • 77
  • 82
user2692482
  • 109
  • 1
  • 1
  • 3

3 Answers3

15

One method would be to reverse the file, replace only the first match, and then reverse it back again.

tac <file> | sed '1 s/boy/boys/' | tac | sponge <newfile>

tac will "concatenate and print files in reverse". sponge will "soak up standard input and write to a file". It's in the "moreutils" package on debian.

R.F
  • 335
  • 3
  • 8
chooban
  • 9,018
  • 2
  • 20
  • 36
  • 4
    What's the benefit of piping to `sponge` compared with `tac > newfile`? The disadvantage, if the data is big, is that there's an extra pipe which the data has to be copied into and out of, which slows things down. – Jonathan Leffler Aug 18 '13 at 04:26
  • Just what my fingers went for as I thought about the problem, really. It's not a robust, all-purpose solution, I'll grant you. – chooban Aug 18 '13 at 08:24
  • 1
    When I used `tac > file` to write this back to the same file (so ` = `, intended behaviour like `sed -i`) it ended up blank (even though it worked with stdout), so I wrote it out to another file first and then renamed that. Maybe there's a better solution, but it worked for me. – johnny Mar 21 '18 at 18:29
8

All you need is $:

sed '$s/boy/boys/'
Beta
  • 96,650
  • 16
  • 149
  • 150
4

This might work for you (GNU sed):

sed '1h;1!H;$!d;x;s/.*boy/&s/' file

Slurp the file into memory and substitute the last occurrence of the desired string using greed.

An alternative, less memory intensive solution:

sed '/.*boy/,$!b;//{x;//p;x;h};//!H;$!d;x;s//&s/' file

This uses the hold space to hold previous lines that contain the required string and sheds them when a new occurence of the required string is encountered. At the end of the file the last occurrence is in the hold space and is modified.

Another solution:

sed -z 's/.*boy/&s/' file
potong
  • 55,640
  • 6
  • 51
  • 83
  • This is the only solution that looks for the last pattern match instead of just doing the substitution on the last line. – Benjamin W. Apr 25 '19 at 00:19
  • please explain it. this is not the correct way in Stack. after the solution, we need to explain the way. – Hossein Vatani Jul 19 '22 at 17:05
  • @HosseinVatani the best way to see how both solutions work is to add the `--debug` option and then follow the flow using the input provided. HTH – potong Jul 20 '22 at 10:25