7.3.3.3. ; , && and || construction

The operators ; (list) && (and) and || (or) are used to combine expressions. The ; operator is equivalent with a <return>, it just separates several expressions which will be executed one after the other. The two other operators are short-circuit logical operators. Short circuit means that evaluation is stopped when the total result is known to be true. In practice this means that

expression1 && expression2

will evaluate expression1 and only if this returns an exit code of 0 (true), expression2 is evaluated. On the contrary

::

expression1 || expression2

will evaluate expression1 and only if this returns an exit code other then 0 (false), expression2 is evaluated.

Thus, the following constructions are equivalent

expression1 && expression2      |            expression1 || expression2
                                |
if expression1                  |  if not expression1     |  if expression1
then                            |  then                   |  then
  expression2                   |    expression2          |    :    # do nothing
fi                              |  fi                     |  else
                                |                         |    expression2
                                |                         |  fi

This is sometimes used in following case (compare the first one with the equivalent way here

[ -d /temp0/$USER ] || mkdir /temp0/$USER  # make the directory only if it not already exists
[ -f file ] && source ./file               # source the file only if it exists

Another case where this short circuiting is usefull, is to convert errors in a successfull exit code. This is the opposite from the example in 7.3.2 where we converted the error-code in a non-error-code.

To suspend temporary the effect of the ‘-e’ option, one can use set +e in the script, as written here for the -x option. We can also do it using a short circuiting construction.

For example, we can consider grepping a non-existing file not a fatal error. The following script will however fail at line 3 (because of the -e switch):

#!/bin/bash -e
date
c=$(grep -c 42 non-existent)
if [ "$c" == "" ]
then
    echo "42 not found"
elif [ $c -eq 0 ]
then
    echo "42 not found"
else
    echo "42 is found"
fi
date

We can solve this by changing the line to:

c=$(grep -c 42 non-existent) || true

true is a command that doesn’t do anything, but returns an exit code of 0. (false also exists)