Search code examples
zshglobparameter-expansion

zsh ${var##$pat} parameter expansion with pattern var containing globs


It seems zsh doesn't honor globs inside variable patterns, in ${var##$pat} parameter expansions:

$ zsh -c 'pat=/*; var=/etc/; echo "$var $pat"; echo "${var##$pat}"'
/etc/ /*
/etc/
# sh result: empty

However, if $pat does not contain *, zsh and sh behave similarly:

$ zsh -c 'pat=/; var=/etc/; echo "$var $pat"; echo "${var##$pat}"'
/etc/ /
etc/
# sh result: same

zsh --emulate sh gives, of course, sh-compatible results. But if I want to stay in zsh emulation, is there any setopt option that changes this behavior? I've looked (briefly) in the docs and I can't really find the reason for this difference.


Solution

  • In zsh, variable contents will only be treated as a pattern if you ask for that, with a ${~spec} expansion or the (very broad and therefore slightly dangerous) GLOB_SUBST option:

    pat=/*t
    var=/etc/
    print "${var##$pat}"
    #=> /etc/
    print "${var##$~pat}"
    #=> c/
    setopt glob_subst
    print "${var##$pat}"
    #=> c/
    

    This is described in the zshexpn man page, in the section for string substitution expansion ${name/pattern/repl}.