22.2.6 [
Although technically equivalent, test is preferable to
[ in shell code written in conjunction with Autoconf, since
`[' is also used for M4 quoting in Autoconf. Your code will be
much easier to read (and write) if you abstain from the use of `['.
Except in the most degenerate shells, test is a shell builtin
to save the overhead of starting another process, and is no slower than
`['. It does mean, however, that there is a huge range of features
which are not implemented often enough that you can use them freely
within a truly portable script. The less obvious ones to avoid are
`-a' and `-o' -- the logical `and' and `or'
operations. A good litmus test for the portability of any shell feature
is to see whether that feature is used in the source of Autoconf, and it
turns out that `-a' and `-o' are used here and
there, but never more than once in a single command. All the same, to
avoid any confusion, I always avoid them entirely. I would not use the
following, for example:
Instead I would run test twice, like this:
The negation operator of test is quite portable and can be
used in portable shell scripts. For example:
|
if test ! foo; then bar; fi
|
The negation operator of if is not at all portable and should
be avoided. The following would generate a syntax error on some shell
implementations:
|
if ! test foo; then bar; fi
|
An implication of this axiom is that when you need to branch if a
command fails, and that command is not test , you cannot use
the negation operator. The easiest way to work around this is to use
the `else' clause of the un-negated if , like this:
|
if foo; then :; else bar; fi
|
Notice the use of the : builtin as a null operation when
foo doesn't fail.
The test command does not cope with missing or additional
arguments, so you must take care to ensure that the shell does not
remove arguments or introduce new ones during variable and quote
expansions. The best way to do that is to enclose any variables in
double quotes. You should also add a single character prefix to both
sides in case the value of the expansion is a valid option to
test :
|
$ for foo in "" "!" "bar" "baz quux"; do
> test x"$foo" = x"bar" && echo 1 || echo 0
> done
0
0
1
0
|
Here, you can see that using the `x' prefix for the first operand
saves test from interpreting the `!' argument as a real
option, or from choking on an empty string -- something you must always
be aware of, or else the following behaviour will ensue:
|
$ foo=!
$ test "$foo" = "bar" && echo 1 || echo 0
test: argument expected
0
$ foo=""
$ test "$foo" = "bar" && echo 1 || echo 0
test: argument expected
0
|
Also, the double quote marks help test cope with strings that
contain whitespace. Without the double quotes, you will see this errors:
|
$ foo="baz quux"
$ test x$foo = "bar" && echo 1 || echo 0
test: too many arguments
0
|
You shouldn't rely on the default behaviour of test (to return `true'
if its single argument has non-zero length), use the `-n' option
to force that behaviour if it is what you want. Beyond that, the other
thing you need to know about test , is that if you use operators
other than those below, you are reducing the portability of your code:
- `-n' string
- string is non-empty.
- `-z' string
- string is empty.
- string1 = string2
- Both strings are identical.
- string1 != string2
- The strings are not the same.
- `-d' file
- file exists and is a directory.
- `-f' file
- file exists and is a regular file.
You can also use the following, provided that you don't mix them within
a single invocation of test :
- expression `-a' expression
- Both expressions evaluate to `true'.
- expression `-o' expression
- Neither expression evaluates to `false'.
|