What you did doesn't work in bash either except in very simple examples.
$ testif 'hello world = hello world'
bash: [: too many arguments
false
$ testif '"hello world" = "hello world"'
bash: [: too many arguments
false
$ testif '* = *'
(usually false with an error message, but it depends on the files in the current directory)
Even your simple example doesn't work in zsh because unlike other sh-like shells, in zsh, $1
really means “take the value of the first argument” (almost: if the expansion results in an empty word, it's removed altogether). In bash and other sh-like shells, $1
means “take the value of the first argument, split it into words and treat each word as a glob pattern” which is almost never what you want.
You can pass a condition in the syntax of the test
/single-brackets command as separate arguments.
testif () {
if [ "$@" ]; then echo true; else echo false; fi
}
This works (with the limitations of the [
command, e.g. no &&
and ||
operators.
$ testif '*' = '*'
true
$ testif hello = hello
true
$ testif 'hello world' = 'hello world'
true
$ testif 0 = 00
false
$ testif 0 -eq 00
true
There's rarely a good reason to pass a [
condition around, though. You might as well pass the whole command. This not only lets you pass other kinds of conditions (e.g. grep …
or if systemctl is-active …
), but if you need more than a simple command, you can define an auxiliary function.
testif () {
if "$@"; then echo "true"; else echo "false"; fi
}
$ testif [ 'hello world' = 'hello world' ]
true
$ testif grep -q : /etc/passwd
true
Another approach would be to pass the whole command as a single string, and use eval
inside the function.
testif () {
if eval "$1"; then echo true; else echo false; fi
}
$ testif '[ "hello world" = "hello world" ]'
true
$ testif '[ "hello world" = "h*" ]'
false
$ testif '[[ "hello world" = "h*" ]]'
false
$ testif '[[ "hello world" = h* ]]'
true
$1
to$=1
. 3. don't ever usea && b || c
-- it's not similar toa ? b : c
orif a; then b; else c; fi
.