Back: Source
Forward: Variables
 
FastBack: Variables
Up: Sh Implementation
FastForward: Environment
Top: Autoconf, Automake, and Libtool
Contents: Table of Contents
Index: Index
About: About this document

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:

 
test foo -a bar

Instead I would run test twice, like this:

 
test foo && test bar

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'.


This document was generated by Gary V. Vaughan on February, 8 2006 using texi2html