The test
command is not told an argument is meant to be an operator or an operand. For example, the shell code symbol='='; test -z "$symbol"
invokes the command test
with the arguments -z
and =
. It's up to the test
command to figure out that -z
is meant to be an operator and =
is meant to be an operand to that operator.
In most cases, there is at most one syntactically correct interpretation. For example, since there are no unary postfix operators, the only way to parse two arguments is if the first argument is a unary prefix operator and the second argument is its operand. Thus test -z =
can only mean to apply the -z
(is-string-empty) operator to the string =
.
As soon as there are three or more arguments, some edge cases are ambiguous. For example, test '(' -a ')'
could be the -a
operator applied to the bare strings (
and )
, or the bare string -a
in parentheses. (I can't think of an ambiguous parsing with three arguments that gives different results.)
Older implementations of the test
command had buggy parsers that did not accept some short unambiguous cases such as -z =
: the parser decided that =
in second position was a binary operator, then realized that there was no right operand for this operator. Sven Mascheck's Bourne shell page lists historical implementations that bugged on test -a =
; this includes both Bourne implementations and ancient versions of ksh.
All modern implementations do what you'd expect if given two or three arguments that are valid. This (and a little more) is mandated by POSIX.
The [
command has the same pitfalls as test
because it's the same command except for requiring a ]
as the final argument.
The [[ … ]]
shell syntax available in some modern shells (ksh, bash, zsh) does not have the same problem because it's parsed differently inside the shell. [[ -z "$symbol" ]]
is parsed as the -z
operator applied to a string; even if the value of symbol
is an equal sign, the word =
does not appear literally in the command, so it cannot refer to the operator =
.
Unless you're working with ancient systems that haven't been supported by their vendors (or perhaps are still supported in some form in some rare niche industries), you will not encounter shells that choke on test -z "$symbol"
in the real world. If a book mentions this, it's seriously out of date; consider using better resources. Better books may be prohibitively expensive in third-world countries, but there's a lot of free stuff on the Internet and some of it is actually good.
bash
, the book has a different interpreter in mind. – Artem S. Tashkinov Apr 15 '21 at 07:58bash
or something else? How old is this book? What book is it? – terdon Apr 15 '21 at 08:10/bin/test
? – Chris Davies Apr 15 '21 at 08:27test
don't fail. They first check the number of arguments. This way they know=
is the operator intest -z = -z
ortest -z = +z
; and they know=
is not an operator intest -z =
. – Kamil Maciorowski Apr 15 '21 at 08:58sh: test: argument expected
). – fra-san Apr 15 '21 at 10:12sh
on Solaris <=10, old versions ofdash
). The most interesting question — why does a book published in 2016 uses an uncommon, non-POSIX shell? — still stands, of course. – fra-san Apr 15 '21 at 11:03obosh
from theschilytools
. – schily May 24 '21 at 05:43