Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

zsh: if [[ why-double-brackets ]]

568 views
Skip to first unread message

shea martin

unread,
Jan 30, 2005, 1:53:13 PM1/30/05
to
I am contemplating moving from bash to zsh. I am going though the 'zsh
users guide'. I notice all the if constructs seem to use double
brackets. Yet most of the examples work with single brackets. What it
the difference (in a nutshell).

i.e.
if [[ -e somefile.txt ]]
then
print found somefile.txt
fi

Thanks,

~S

Stephane CHAZELAS

unread,
Jan 31, 2005, 3:36:07 AM1/31/05
to
2005-01-30, 18:53(+00), shea martin:
[...]

"[" is a shell builtin command, so that

[ the test expression ]

is parsed as a simple command, with all the ordinary syntax for
simple command line (| is a pipe, > is a redirection operator,
&& delimits commands, $var expands var it doesn't refer to the
value of var, */? trigger filename generation...).

[[ the test expression ]]

can be seen as some kind of quotes. What's inside is a test
expression with the particular syntax of the test expression
which is generally more intuitive, because you don't need first
to think what arguments "[" will get (that's "[" that builds the
test expression out of its arguments) but just what is the test
expression you want to be evaluated.

[[ $a = *foo* || ( $file1 -nt $file2 && $a > $b ) ]]

Above, "||", "(", ">" and "&&" are special shell operators, so
you couldn't have used them asis in a "[" expression, but above
there's no problem as "[[" protects them.

With "[", you would have had to write it as:

case $a in
*foo*) true;;
*) [ "$file1" -nt "$file2" ] && [ "$a" \> "$b ];;
# [ "$file1" -nt "$file2" -a "$a" \> "$b" ] would not have
# been reliable, because remember that "[" only gets a list of
# arguments where all the variables have been expanded so that
# it may have a hard time guessing what was the test you
# wanted to perform if for instance $file1 is "(" and $file2
# is "=" and so on...
esac

Note that "[[" was first introduced in ksh, then in zsh and
bash. But it is not POSIX. So, you may not use it if you intend
to write scripts not intended for your own use only.

--
Stéphane

Thorsten Kampe

unread,
Jan 31, 2005, 6:51:23 AM1/31/05
to
* shea martin (2005-01-30 18:53 +0100)

> I am contemplating moving from bash to zsh. I am going though the 'zsh
> users guide'. I notice all the if constructs seem to use double
> brackets. Yet most of the examples work with single brackets. What it
> the difference (in a nutshell).

"Advanced Bash Scripting Guide":
"Using the [[ ... ]] test construct, rather than [ ... ] can prevent
many logic errors in scripts. [...] For example, the &&, ||, <, and >
operators work within a [[ ]] test, despite giving an error within a [
] construct."

zsh Userguide:
"'[[' is treated specially, which allows the shell to do some extra
checks and allows more natural syntax. For example, you may know that
in sh it's dangerous to test a parameter which may be empty ...".

Thorsten

Stephane CHAZELAS

unread,
Jan 31, 2005, 9:28:36 AM1/31/05
to
2005-01-31, 11:51(+00), Thorsten Kampe:
[...]

> zsh Userguide:
> "'[[' is treated specially, which allows the shell to do some extra
> checks and allows more natural syntax. For example, you may know that
> in sh it's dangerous to test a parameter which may be empty ...".
[...]

Why? I've never encountered such a problem. Maybe the guide is
speaking of badly written code where parameters are not quoted.

[ "$a" = "$b" ]

Would work perfectly if either $a or $b is empty.

However, it may not work correctly with some shell/test
implementations if $a is "!" or "(" or "-f"...

~$ a="!" b="!" dash -c '[ "$a" = "$b" ]'
[: 1: !: unexpected operator

The problem is that the parameter expansion is done before the
parsing of the test expression is done.

While in [[ $a = "$b" ]] (note the mandatory quotes around $b
unless you want to consider $b as a pattern), it's recognized by
the shell as a equality test, and then afterwards, the value of
the variables are considered.

Note that:

[ "$a" = "$b" ]

should work OK with every POSIX conformant shell, whatever the
values of $a and $b. But, dash claims POSIX conformance and
fails. That's why you generally see:

[ "x$a" = "x$b" ]

instead

Note that POSIX says that, when "[" gets more than 5 arguments,
("[", "]" + 3), the behavior is not required to be reliable.

--
Stéphane

0 new messages