Is there any concise zsh regular expression parameter expansion to replace the last match of a pattern?
I know very ugly way of doing it, but I'd prefer a cleaner, more concise syntax:
# param, pattern & replacement are placeholders below for real values
${(*S)param/%pattern(#b)(*)/replacement${match[1]}}
Which enables extended_glob, chooses shortest match, matches the pattern against the end of the value of $param
, specifies the pattern, enables back references, saves the text from after the last match of the pattern in a back reference, and then replaces the match with my replacement, using the back reference to reinstate the text from after the match.
${match[1]}
can be shortened to$match[1]
and*
omitted if you turn extendedglob on. Note that withFooFoo
as the pattern, on an input likeFooFooFooFooFoo
, that can be seen as having two occurrences ofFooFoo
followed byFoo
, that givesFooFooFooreplacement
instead ofFooFooreplacementFoo
.${param}
, even when unnecessary, for consistency (& I think it's easier to read). I also like to use(*)
if I can instead ofsetopt
. Good that you mentioned options to shorten the solution for others, though, who might have other stylistic preferences.