Pattern matching in a zsh conditional expression
Solution 1
[ $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.
Solution 2
*test*
is not a valid regex pattern. The *
is a repetition operator and needs something to repeat. It's very likely you want .*test.*
, although that isn't necessary with regex since it is not anchored by default. You could just look for test
However you cannot match regex patterns with the =
operator, you need =~
.
precmd () {
local x=test
if [[ $x =~ test ]]; then
echo 'hello'
fi
}
Tyler Kelly
Updated on September 18, 2022Comments
-
Tyler Kelly over 1 year
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 inprecmd
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
-
Tyler Kelly over 4 yearshook functions:
http://zsh.sourceforge.net/Doc/Release/Functions.html
and regex is a bit of a misnomer, actually a globbing pattern:http://zsh.sourceforge.net/Doc/Release/Expansion.html#Filename-Generation
-
Tyler Kelly over 4 yearszsh.sourceforge.net/Doc/Release/Conditional-Expressions.html see edit above as well.
-
Tyler Kelly over 4 yearsthe content in the function works outside of that function as stated in the Q, so it seems like I am using their pattern matching correctly. this just doesn't work properly when placed in the precmd function
-
-
Gilles 'SO- stop being evil' over 4 yearsWhy switch to regexp matching with
=~
? You can keep the wildcard syntax and the=
operator. The only thing that needs to change is to use[[
instead of[
. -
jesse_b over 4 years@Gilles'SO-stopbeingevil': I'm no zsh expert and OP said they wanted regex.
-
Stéphane Chazelas over 4 yearsThat's more a bash (3.2+) answer. In zsh, you can quote the regexps, and generally want to if they contain special characters. Use
[[ $x =~ '.*test.*' ]]
or[ "$x" '=~' '.*test.*' ]
or[[ $x = *test* ]]
(no quote there), or[[ $x =~ test ]]
-
Stéphane Chazelas over 4 yearsOr use the standard
case $x in (*test*) ... ;esac
syntax.