sections in this module City College of San Francisco - CS160B
Unix/Linux Shell Scripting
Module: Conditionals
module list

How ifs work

The if statement uses the exit status of a Unix command to decide whether to execute a sequence of commands:

if cmd1; then
xxx
fi

Execution of this if statement proceeds as follows:

An example with grep shows how this works:

if grep 'Greg' file1; then
echo 'file1 had at least one line that contained Greg'
elif grep 'Susan' file1; then
echo 'file1 did not have any lines that contained Greg'
echo 'but file1 did have at least one line that contained Susan'
elif grep 'Juan' file1; then
echo 'file1 did not have any lines that contained Greg or Susan'
echo 'but file1 did have at least one line that contained Juan'
else
echo 'file1 did not have any lines that contained Greg, Susan, or Juan'
fi

The first if/elif clause whose command succeeds is executed. If none succeed, the else clause is executed, if one exists.

If we execute this if statement on a file file1 that contains the single line 

this line contains Susan on it

we get this output:

this line contains Susan on it
file1 did not have any lines that contained Greg
but file1 did have at least one line that contained Susan

Remember, grep outputs the lines that contain the pattern. Thus, the first line in the output above is simply the line that matched!  This can be very confusing to someone using your program.

Suppose your program requires the user to provide the path to an input file. Internally, you want to make a copy of the file before working on it. You might combine the code to copy the file with a diagnostic about an incorrect filename like this:

if ! cp "$userfile" $$.tmp1; then
echo "file '$userfile' is not readable" >&2
fi

This looks fine, but if the user makes a mistake when entering the filename, your program output looks like this:

cp: cannot access mysoucefile: No such file or directory
file 'mysoucefile' is not readable

Here, your diagnostic has been intermingled with the error message from cp! Since the user had no idea the cp command was being used, this can be very confusing, and is not professional.

Controlling the output of your commands

The purpose of placing a command in an if statement is to take some action if it succeeds (or fails). In this case, you want to suppress any error messages the command produces:

if ! cp "$userfile" $$.tmp1 2>/dev/null; then
echo "file '$userfile' is not readable" 
fi

We have introduced something new here: redirecting error output. As some of you may know, error messages are not output to standard output - they are ouput to the pathway standard error. We want to suppress the error message which would normally come from cp because we are producing our own error message. We can do this by redirecting standard error to /dev/null to throw it away. To redirect standard error you place standard error's number (2) as a prefix on the redirection operator, as we did above. (We will cover these redirection operators in the next module.) You can do the same with standard output, or with both, if you don't want to see it:

if grep 'Greg' "$userfile" > /dev/null 2>/dev/null ; then
echo "Greg found in '$userfile'"
fi

In the command above, grep's output of lines that match will be suppressed, as will any message about a missing or unreadable file. If you want to be more complete in your testing so that both possibilities are covered completely, you should check the file's existence and permissions before using it. This requires using the test command, which is part of our next section:

if test ! -r "$userfile" -o ! -f "$userfile"; then
echo "'$userfile' is not a readable file" 
exit 1
fi

After we discuss redirection operators in the next module, we will also learn how to output our error messages to standard error, like any standard Unix command.

Indentation

Indentation is very important to enable the reader to follow your if statements. As an example, look at the following if statements without indentation:

if test -r "$userfile" -a  -f "$userfile"; then
if grep 'Greg' "$userfile" > /dev/null 2>/dev/null ; then
echo "Greg found in '$userfile'"
fi
else
echo "'$userfile' is not a readable file"
exit 1
fi

Without indentation, even this fairly simple sequence is much less readable than the indented version:

if test -r "$userfile" -a  -f "$userfile"; then
if grep 'Greg' "$userfile" > /dev/null 2>/dev/null; then
echo "Greg found in '$userfile'"
fi
else
echo "'$userfile' is not a readable file" 
exit 1
fi

Using !

The ! operator appears two common places in if statement: to negate a clause of a test expression and to negate the exit status of a command. Some users find one simpler than the other. Although they have different meanings, the result can be the same. 

In the example below, the user needs a writable directory. If the variable that holds the directory path does not refer to a writable directory, an error should be output and the program aborted:

if test ! -d "$dir" -o ! -w "$dir" ; then
echo "$(basename "$0"): '$dir' must be a writable directory" 
exit 1
fi

This logic can be a bit difficult to understand until you get used to it. There are two conditions: the path must be a directory, and the path must be writable. Both must be true if we are to proceed. Thus, if either is not true, we must abort. Hence we must change AND to OR.

It may be simpler to write the test command to test what we want to be true, then negate the result:

if ! test -d "$dir" -a -w "$dir"; then
echo "$(basename "$0"): '$dir' must be a writable directory" 
exit 1
fi

Whichever of these solutions makes the most sense to you is the one you should use. Be aware, however, that the ! operator as applied to commands is not available in all Bourne-type shells.

 Preview question: What is the problem with the following command?
if [-f "$file" -a -r$file ]; then
cat $file
fi
There are four bugs in this sequence: two will cause syntax errors immediately, and two are data-dependent. Can you find them? (Hint: they are all due to spacing or quoting.)

Prev This page was made entirely with free software on linux:  
Kompozer
and Openoffice.org    
Next

Copyright 2009 Greg Boyd - All Rights Reserved.

Document made with Kompozer