Prev (Loops) | Next (Case) |
test
is not often called directly. test
is more frequently
called as [
. [ is a symbolic link to test, just to make shell programs more
readable. If is also normally a shell builtin (which means that the shell itself will interpret
[ as meaning test, even if your Unix environment is set up differently):
$ type [ [ is a shell builtin $ which [ /usr/bin/[ $ ls -l /usr/bin/[ lrwxrwxrwx 1 root root 4 Mar 27 2000 /usr/bin/[ -> testTest is a simple but powerful comparison utility. For full details, run
man test
on your system, but here are some usages and typical examples.
Test is most often invoked indirectly via the if
and
while
statements. It is also the reason you will come
into difficulties if you create a program called test
and
try to run it, as this shell builtin will be called instead of your
program!
The syntax for if...then...else...
is:
if [ ... ] then # if-code else # else-code fiNote that
fi
is if
backwards! This is used again
later with case and esac
.if [ ... ]; then # do something fi
Try the following code snippet, before running it set the variable X to various values (try -1, 0, 1, hello, bye, etc). You can do this as follows (thanks to Dave for pointing out the need to export the variable, as noted in Variables - Part I.):
$ X=5 $ export X $ ./test.sh ... output of test.sh ... $ X=hello $ ./test.sh ... output of test.sh ... $ X=test.sh $ ./test.sh ... output of test.sh ...Then try it again, with
$X
as the name of an existing file, such
as /etc/hosts
.
#!/bin/sh if [ "$X" -lt "0" ] then echo "X is less than zero" fi if [ "$X" -gt "0" ]; then echo "X is more than zero" fi [ "$X" -le "0" ] && echo "X is less than or equal to zero" [ "$X" -ge "0" ] && echo "X is more than or equal to zero" [ "$X" = "0" ] && echo "X is the string or number \"0\"" [ "$X" = "hello" ] && echo "X matches the string \"hello\"" [ "$X" != "hello" ] && echo "X is not the string \"hello\"" [ -n "$X" ] && echo "X is of nonzero length" [ -f "$X" ] && echo "X is the path of a real file" || echo "No such file: $X" [ -x "$X" ] && echo "X is the path of an executable file" [ "$X" -nt "/etc/passwd" ] && echo "X is a file which is newer than /etc/passwd"
if
statements.
As we see from these examples, test
can perform many tests on
numbers, strings, and filenames.
There is a simpler way of writing if
statements: The &&
and
||
commands give code to run if the result is true.
#!/bin/sh [ $X -ne 0 ] && echo "X isn't zero" || echo "X is zero" [ -f $X ] && echo "X is a file" || echo "X is not a file" [ -n $X ] && echo "X is of non-zero length" || echo "X is of zero length"This syntax is possible because there is a file (or shell-builtin) called
[
which is linked to test
. Be careful using this
construct, though, as overuse can lead to very hard-to-read code. The
if...then...else...
structure is much more readable. Use of the
[...]
construct is recommended for while loops and trivial sanity
checks with which you do not want to overly distract the reader. Note that when you set X to a non-numeric value, the first few comparisons result in the message:
test.sh: [: integer expression expected before -lt test.sh: [: integer expression expected before -gt test.sh: [: integer expression expected before -le test.sh: [: integer expression expected before -geThis is because the -lt, -gt, -le, -ge, comparisons are only designed for integers, and do not work on strings. The string comparisons, such as
!=
will happily treat
"5" as a string, but there is no sensible way of treating "Hello" as an
integer, so the integer comparisons complain. echo $X | grep -v [0-9] > /dev/null 2>&1 if [ "$?" -eq "0" ]; then # If the grep found something other than 0-9, then it's not an integer. echo "Sorry, wanted a number" else # The grep found only 0-9, so it's an integer. We can safely do a test on it. if [ "$X" -eq "7" ]; then echo "You entered the magic number!" fi fiIn this way you can
echo
a more meaningful
message to the user, and exit gracefully. The $?
variable is explained
in Variables - Part II, and grep
is
a complicated beast, but grep -v [0-9]
finds only those lines of text which don't contain
any digits (0-9). The >/dev/null 2>&1
directs any
output or errors to the special "null" device, instead of going to the user's screen.
We can use test in while loops as follows:
#!/bin/sh X=0 while [ -n "$X" ] do echo "Enter some text (RETURN to quit)" read X echo "You said: $X" done
while [ -n "$X" ]
. Without those quotes, there is nothing to test when $X is empty. $ ./test2.sh Enter some text (RETURN to quit) fred You said: fred Enter some text (RETURN to quit) wilma You said: wilma Enter some text (RETURN to quit) You said: $This can be tidied up with another test within the loop:
#!/bin/sh X=0 while [ -n "$X" ] do echo "Enter some text (RETURN to quit)" read X if [ -n "$X" ]; then echo "You said: $X" fi doneNote also that I've used two different syntaxes for
if
statements on this page. These are:
if [ "$X" -lt "0" ] then echo "X is less than zero" fi .......... and ........ if [ ! -n "$X" ]; then echo "You said: $X" fiYou must have a break between the
if
statement and the then
construct. This can be a semicolon or
a newline, it doesn't matter which, but there must be one or the other between the if
and the then
.
It would be nice to just say:
if [ ! -n "$X" ] echo "You said: $X"but the
then
and fi
are absolutely required.
Prev (Loops) | Next (Case) |