ZSH Gem #18: Regexp search and replace on parameters
In ZSH you can easily perform regexp search and replace operations on shell parameters. The only function you need for this is regexp-replace.
Regexp search and replace can be very useful when writing shell scripts which need to process input data, directory names, process trees etc. You assign the string which you need to work on to a parameter and then run the replace function on it. But before you can do anything, you need to load the function first:
autoload -U regexp-replace
The syntax of regexp-replace is as follows:
regexp-replace VARNAME REGEXP REPLACE
where VARNAME is the name of the variable, REGEXP the regular expression and REPLACE the replace string.
As an example of how to use regexp-replace let us replace all occurrences of /foo/bar in the $PATH variable. So let's add that first of all:
PATH="$PATH:/foo/bar"
echo $PATH
There we have it. Now let us remove that entry again:
regexp-replace PATH ':/foo/bar' ''
That will replace our newly added string with an empty string. Of course this was a very basic pattern. But we can use the full POSIX extended regexp syntax and if we enable the option RE_MATCH_PCRE
setopt re_match_pcre
we can even use full Perl compatible regular expressions (provided ZSH was built with PCRE support). Let's do that and replace all entries starting with /usr/ with foo:
regexp-replace PATH '(^|:)/usr/[^:]*' ':foo'
Unfortunately there is no direct way to use back references for each parenthesis expression in the replace pattern, but there are at least some special variables: $MATCH contains the matched portion, $1 contains the variable name and $2 contains the pattern. For instance to append /subdir to the paths starting with /usr instead of replacing the whole thing, we could write
regexp-replace PATH '(^|:)/usr/[^:]*' '$MATCH/subdir'
Mind the single quotes! $MATCH is not an actual shell parameter but rather a placeholder which is replaced by the regexp-replace function. If you would use double quotes or even no quotes, you'd get an empty string (except $MATCH already has some value assigned to it, but normally that's not what you want anyways). The same applies to $1 and $2.
regexp-replace is a nice addition to ZSH's parameter expansion patterns. It's easy to use and in most cases more than sufficient.
Read more about regexp-replace: