The power of programming lies in the ability to have the computer make
a decision based on one or more choices (either embedded right in the
program or provided by the user when the program is executed).
This decision-making process is called branching, because of the
obvious analog of a tree-branch system.
The tool provided by the Bourne shell to build these branching systems
if:then:else construct, which has the following form:
if statement_A then statement_B statement_C else statement_D fi statement_E
What happens here is that
statement_A (or more correctly
condition_A) is attempted.
If a true value is returned,
statement_B and then
statement_C are carried out, followed by
If a false value is returned from
statement_D is executed followed by
fi statement signals the end of the construct and allows
sequential execution of the following commands to resume.
The interesting part of the branching process is how the decision is
The programmer sets up a test (
Statement_A can be a specific condition (is A bigger than B) or
it can be an expression.
When the shell executes a command or an expression it returns a value
(called the exit status); if the command executes without problems, a
true value is returned, otherwise a false value is returned.
It may seem strange to have a command act as a test condition, but
this is actually a very convenient way to handle errors and other
For example a user may want to automatically print a file, and have an
error returned if the file does not exist:
if ls plot.ps then lpr plot.ps else echo ":::: ERROR FILE DOESN'T EXIST ::::" fi
If the file does not exist the shell will produce an error message,
separate from the message in the
This error message is what the shell returns automatically if the
argument (filename) for the list command does not exist.
The stderr can be redirected form the screen to a file which
would keep the error messages from coming up on the screen, but it
would also leave a file containing the message in the user's account.
Unix provides a tool called the null device to handle situations like this.
The null device acts like a file that is emptied as soon as anything is
placed in it.
Any unwanted output can be redirected to the null device and it will
then be immediately disposed of.
Care must be taken when sending anything to the null device as nothing
can be recovered once it has been sent there.
The following modification to the line containing the
command will send stderr to the null device:
if ls plot.ps 2>/dev/null
The above demonstrates how a return value, or exit status, can be used
in a test, but what about other types of tests?
Suppose two strings are to be compared, and the result of the
comparison determines the next step, or if the status of a file
determines the branch taken; what then?
The Bourne shell comes with two ways to test conditions, the explicit
method: the test statement; and the shorthand method: square brackets
The full general test expression works as follows:
$ string1="APPLE" $ string2="ORANGE" $ test "$string1" = "$string2" $ echo $? 1
1 that is returned is a false value.
In the Bourne shell an exit value of zero is translated as a true
value whereas a non-zero value is translated as a false
It is also important to note that the white space between the
= sign and the values on either side are required.
In assignment expressions there would be no white space around the
When used in a decision branch the above example is a lengthy way to
get to the result of the test.
A more direct test would take the following form:
if [ "APPLE" = "ORANGE" ] then (A) else (B) fi
B will be executed, as the strings are
clearly not equivalent.
Again, the white space around the brackets is necessary.
This is a much more elegant method of testing and will be the
preferred choice for the remainder of this chapter.
The three conditions that will need to be tested are: string comparisons, file status and integer comparisons.