-1

I'm tying to replace the last occurrence of a word in a file.

hello
bye
bye
bye
hello

I am able to replace it by indicating the line number.

sed -i '4 s/bye/adieu' file

Also, if the occurrence is in the last line.

sed -i '$ s/hello/salut' file

But, how can I find and replace the last bye without indicating the line number?

Enlico
  • 23,259
  • 6
  • 48
  • 102
Jota
  • 69
  • 1
  • 1
  • 4
  • Does this answer your question? [KSH: sed command to search and replace last occurrence of a string in a file](https://stackoverflow.com/questions/26249244/ksh-sed-command-to-search-and-replace-last-occurrence-of-a-string-in-a-file) – Wiktor Stribiżew Sep 22 '21 at 14:11
  • Thanks Wiktor. As mentioned in the post of the provided link, using tail -2 file | sed 's/bye/adieu/g' it works, but it is necessary to know the position of the last occurrence. – Jota Sep 23 '21 at 05:59

2 Answers2

1

This is a bit gross and probably not recommended for large files, but it should work:

sed -zE '$ s/(.*)bye/\1adieu/' file

where -z makes Sed consider the whole file as a single line with \n interspersed, and -E is to use () instead of \(\).

If there's a chance that a line contains bye but is not just bye, as in goodbye/good bye/whatever, than you can go with

sed -zE '$ s/(.*)(^|\n)bye($|\n)/\1adieu/' file
Enlico
  • 23,259
  • 6
  • 48
  • 102
0

One possible solution using tac | gnu-sed | sed:

tac file | sed '0,/^bye$/ s//adieu/' | tac

hello
bye
bye
adieu
hello

Details:

  • tac prints file in reverse
  • 0,/^bye$/ matches a line from beginning to first occurrence of bye line
  • s//adieu/ substitutes that line with adieu
  • tac prints file in reverse again to get original order

Alternatively this awk solution would work in any version of awk:

awk 'FNR == NR {if ($0 == "bye") last = FNR; next}
FNR == last {$0 = "adieu"} 1' file file

hello
bye
bye
adieu
hello
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • I had already been using tac, but it only displays the output, it does not edit the file. Thanks anubhava. – Jota Sep 23 '21 at 06:25
  • 1
    For saving changes use: `tac file | sed '0,/^bye$/ s//adieu/' | tac > _tmp && mv _tmp file` – anubhava Sep 23 '21 at 08:19