Search code examples
bashshellawksed

How to replace only the last occurrence in a file?


Having a file containing repeated commented lines like:

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"

I want to add a line only after the last occurrence resulting in

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"
ScriptAlias /cgi-bin/ "mypath"

To do so I'm using this command:

sed -i 's:^\(.*ScriptAlias /cgi-bin/.*\):\1 \nScriptAlias /cgi-bin/ "mypath":' file

But this results in adding my line after each occurence like:

# ScriptAlias /cgi-bin/ "somepath"
ScriptAlias /cgi-bin/ "mypath"
# ScriptAlias /cgi-bin/ "otherpath"
ScriptAlias /cgi-bin/ "mypath"

How can I tell sed to replace only the last occurence?

If there's no way to solve it using sed (as said in comments), please provide alternatives reaching the same result, thanks.

The repeated lines can be separated and with other lines between them like

# ScriptAlias /cgi-bin/ "somepath"
# ScriptAlias /cgi-bin/ "otherpath"

# ScriptAlias /cgi-bin/ "another-path"
ScriptAlias /foo/ "just-jump"
# ScriptAlias /cgi-bin/ "that's the last"

Solution

  • Use tac so you print your new line the first time you see the pattern:

    tac file | awk '/ScriptAlias/ && ! seen {print "new line"; seen=1} {print}' | tac