You want to check if you have the right number of arguments and take actions accordingly. You need a branching construct.
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.)
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:
iflist;
thenlist;
fi
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.
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).
18.226.88.110