Zsh – Pattern Matching in a Zsh Conditional Expression

regular expressionstringtestwildcardszsh

I am having trouble with pattern matching in zsh's hook function precmd. I have the following:

precmd(){
   local x='test'
   if [ $x = '*test*' ]; then
      echo 'hello'
   fi
}

which does not print hello ever. I've tested this code with a normal zsh test.zsh that works fine, and I've tried w/o the regex in precmd and got things to print out fine as well. Any clue as to why this isn't working as expected?

$ zsh --version
zsh 4.3.11 RHEL 

Best Answer

[ $x = '*test*' ] tests whether the string resulting from expanding $x, which is text, is equal to the string resulting from expanding '*test*', which is *text*.

To test whether the value of the variable x matches the pattern *test*, you need to use the = or == operator of zsh conditional expressions, which are written within double brackets [[ … ]]. Furthermore special characters in the pattern must be unquoted, otherwise they stand for themselves. Thus:

if [[ $x == *test* ]]; then …

The syntax of conditional expressions is similar to the syntax of expressions that you can use within single brackets [ … ], but not identical. [ is parsed like an ordinary command; in fact, it's a built-in command with a one-character name, which is identical to the test builtin except that [ requires an additional argument at the end which must be ]. [[ … ]] is a distinct grammatical construct, which allows it to have shell special characters inside. [ $x = *test* ] would expand *test* to the list of matching file names (globbing) and the test builtin would end up parsing the result of that. [[ $x = *test* ]] parses *test* as part of conditional expression parsing which does not invoke globbing.

Related Question