There are two compact versions of the if test which you may see from time to time; these tests operate on a single statement and determine whether a subsequent command is to be executed. They are && (AND IF) and || (OR IF). These operators evaluate $? for the previous command. && executes the following command if the previous command succeeded; || executes the following command if the previous command failed. Note that the execution of the second command is entirely dependent on the result of executing the first command. Thus, if you write a line with two or more of these operators, each command is executed in turn along the line until one of them results in a test failing.
For example, the test to see if a given user is logged on could be
written as follows:
who | grep -e "$1" || echo "$1 is not logged on"
A who listing is piped to grep, which searches for the subject (whose name is the first argument to the script). The OR IF test examines the returned value from grep. If grep failed (that is, if the user is not logged on), a message is printed. If grep succeeded and returned ``0'', no message is needed because grep printed the line from the who listing.
In general, you can use || to execute a command when the previous command has failed, and you can use && to execute a command if the previous command has succeeded.
For example, take the command:
compress $1 || print "Something went wrong compressing $1"
The program compress is executed. When it finishes, its exit value $? is tested by ||. If it is non-zero, the error message is printed.
This compares with the other command:
compress $1 && print "Finished compressing $1"
If the exit value of compress is 0, the message is printed.
A common problem when using the && and || operators is to assume that they are equivalent to the logical operators provided by other programming languages. In fact, these operators are conditional constructs that evaluate strictly from left to right. Consequently it is hazardous to use them for evaluating logically true or false values (like the && or || operators in C). These operators are not strictly equivalent to if ... else ... fi either. For example, the following short script determines if someone is logged in:
if who | grep $1 >/dev/null then echo $1 is logged in else echo $1 is not logged in fiUsing the && and || operators, we might be tempted to rewrite this script more succinctly as follows:
who | grep $1 >/dev/null && echo $1 is logged in || echo $1 is not logged inHowever, this version will execute the second echo incorrectly if the pipe (who | grep $1) fails. The if ... else ... fi version, in contrast, does not exhibit this behavior (despite looking superficially similar in logical terms).