Autoconf, Automake, and Libtool: Test

| ### 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