Branching on Conditions

Problem

You want to check if you have the right number of arguments and take actions accordingly. You need a branching construct.

Solution

The if statement in bash is similar in appearance to that in other programming languages:

if [ $# -lt 3 ]
then
    printf "%b" "Error. Not enough arguments.
"
    printf "%b" "usage: myscript file1 op file2
"
    exit 1
fi

or alternatively:

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.
"
    printf "%b" "usage: myscript file1 op file2
"
    exit 1
fi

Here’s a full-blown if with an elif (bash-talk for else-if) and an else clause:

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.
"
    printf "%b" "usage: myscript file1 op file2
"
    exit 1
elif (( $# > 3 ))
then
    printf "%b" "Error. Too many arguments.
"
    printf "%b" "usage: myscript file1 op file2
"
    exit 2
else
    printf "%b" "Argument count correct. Proceeding...
"
fi

You can even do things like this:

[ $result = 1 ] 
  && { echo "Result is 1; excellent." ; exit 0;   } 
  || { echo "Uh-oh, ummm, RUN AWAY! " ; exit 120; }

(For a discussion of this last example, see Saving or Grouping Output from Several Commands.)

Discussion

We have two things we need to discuss: the basic structure of the if statement and how it is that we have different syntax (parentheses or brackets, operators or options) for the if expression. The first may help explain the second. The general form for an if statement, from the manpage for bash, is:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

The [ and ] in our description here are used to delineate optional parts of the statement (e.g., some if statements have no else clause). So let’s look for a moment at the if without any optional elements.

The simplest form for an if statement would be:

if list; then list; fi

Tip

In bash, the semicolon serves the same purpose as a newline—it ends a statement. So in the first examples of the Solution section we could have crammed the example onto fewer lines by using the semicolons, but it is more readable to use newlines.

The then list seems to make sense—it’s the statement or statements that will be executed provided that the if condition is true—or so we would surmise from other programming languages. But what’s with the if list? Wouldn’t you expect it to be if expression?

You might, except that this is a shell—a command processor. Its primary operation is to execute commands. So the list after the if is a place where you can put a list of commands. What, you ask, will be used to determine the branching—the alternate paths of the then or the else? It will be determined by the return value of the last command in the list. (The return value, you might remember, is also available as the value of the variable $?.)

Let’s take a somewhat strange example to make this point:

$ cat trythis.sh
if ls; pwd; cd $1;
then
    echo success;
else
echo failed;
fi
pwd

$ bash ./trythis.sh /tmp
...
$ bash ./trythis.sh /nonexistant
...
$

In this strange script, the shell will execute three commands (an ls, a pwd, and a cd) before doing any branching. The argument to the cd is the first argument supplied on the shell script invocation. If there is no argument supplied, it will just execute cd, which returns you to your home directory.

So what happens? Try it yourself and find out. The result showing “success” or “failed” will depend on whether or not the cd command succeeds. In our example, the cd is the last command in the if list of commands. If the cd fails, the else clause is taken, but if it succeeds, the then clause is taken.

Properly written commands and built-ins will return a value of 0 (zero) when they encounter no errors in their execution. If they detect a problem (e.g., bad parameters, I/O errors, file not found), they will return some non-zero value (often a different value for each different kind of error they detect).

This is why it is important for both shell script writers and C (and other language) programmers to be sure to return sensible values upon exiting from their scripts and programs. Someone’s if statement may be depending on it!

OK, so how do we get from this strange if construct to something that looks like a real if statement—the kind that you are used to seeing in programs? What’s going on with the examples that began this recipe? After all, they don’t look like lists of statements.

Let’s try this on for size:

if test $# -lt 3
then
    echo try again.
fi

Do you see something that looks like, if not an entire list, then at least like a single shell command—the built-in command test, which will take its arguments and compares their values? The test command will return a 0 if true or a 1 otherwise. To see this yourself, try the test command on a line by itself, and then echo $? to see its return value.

The first example we gave that began if [ $# -lt 3 ] looks a lot like the test statement—because the [ is actually the test command—with just a different name for the same command. (When invoked with the name [ it also requires a trailing ] as the last parameter, for readability and aesthetic reasons.) So that explains the first syntax—the expression on the if statement is actually a list of only one command, a test command.

Tip

In the early days of Unix, test was its own separate executable and [ was just a link to the same executable. They still exist as executables used by other shells, but bash implements them as a built-in command.

Now what about the if(( $# < 3)) expression in our list of examples in the Solution section? The double parentheses are one of several types of compound commands. This kind is useful for if statements because it performs an arithmetic evaluation of the expression between the double parentheses. This is a more recent bash improvement, added for just such an occasion as its use in if statements.

The important distinctions to make with the two kinds of syntax that can be used with the if statement are the ways to express the tests, and the kinds of things for which they test. The double parentheses are strictly arithmetic expressions. The square brackets can also test for file characteristics, but its syntax is much less streamlined for arithmetic expressions. This is particularly true if you need to group larger expressions with parentheses (which need to be quoted or escaped).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.88.110