Tests#

To make full use of conditionals a wide range of tests is helpful. Traditionally there have been two programs test (/usr/bin/test) and [ (/usr/bin/[) which take arguments to build test conditions and logical expressions.

[ is a weird file name to make the expressions more readable. It also expects a closing bracket as its last argument. To test, if $A is equal to 0, the following statements can be used:

test $A -eq 0     # Ok, 3 arguments for test
[ $A -ge 0 ]      # Ok, 4 arguments for [
[$A -ge 0]        # Syntax error, missing spaces

This explains the unusual syntax of the comparison operators and the necessary spaces around the brackets. Bash also provides a built-in command [[ which is very similar to [ and test. It has more features and is easier to handle.

[[ $A -eq 0 ]]    # exit code 0 iff $A is equal to 0

Test operations#

Numerical comparison#

The following table list comparison operators for integer values. It important to note that [[ interprets empty strings a numerical value 0. For example [[ $A -eq 0 ]] with A undefined has exit code 0, while [ $A -eq 0 ] yields an syntax error. Variables do not have to be declared as integers (decalre -i) for these test to work, they just have to valid string representations for integers, e.g. A=10, B=-12, C=013, … Otherwise [[ exits with an error and an exit code other than 0 or 1.

Operator

Math

Meaning

-gt

\(>\)

Greater than

-ge

\(\geq \)

Greater or equal

-lt

\(<\)

Less than

-le

\(\leq\)

Less or equal

-eq

\(=\)

Equal to

-ne

\(\neq\)

Not equal to

Note

Comparison of floating point numbers is seldom used and much more complicated. And extra tools like bc (basic calculator) have to be used. For example, testing $A \(\geq\) $B with floating point numbers is achieved by:

(( $(echo "$A >= $B" | bc) ))

String comparison#

The following table list the string comparison operators for [[. Instead of =, also == can be used to be more in line with most other programming languages.

Operator

Meaning

>

Lexicographical less than

<

Lexicographical greater than

=

Equal to, the right hand side can contain bash wild cards

=~

Equal to, the right hand side can be a regular expression

!=

Not equal to

All comparisons are case-sensitive. And the lexicographical order may depend on the environment (LC_COLLATE).

The equality test = (or ==) accepts shell wildcards on the right hand size, e.g. * or ?. In particular they have to be escaped (on the rhs) for literal matches, e.g.

[[ $A = foo\? ]]

is true only for A=foo?, while [[ $A = foo? ]] evaluates to true for A=foo? or A=food.

The =~ is similar but accepts regular expressions on the right hand size.

[[ $A =~ ^foo.$ ]]

is true for all values of A starting with foo followed by exactly one other character.

File tests#

Often it useful to check if a file exits or its attributes, [[ implements some file tests. All operators in the following table are unary operators, i.e. just take one argument.

Operator

Meaning

-e

File or directory exists

-s

File exists and is non-empty

-x

File is executable

-f

File is a regular file

For example [[ -x my_script.sh ]] has exit code 0 if and only if my_script.sh exists and is executable. A common bash idiom is to check if a file to executable before actually executing it: [[ -x foo.sh ]] && ./foo.sh.

Boolean operators#

To build more complex expressions, simpler ones can be combined by boolean operations. All these are dedicated shell built-ins and treat exit code 0 as “true” and everything else as “false”. However [[ does implement them as well, so they can be used inside and outside of [[-expressions. It is better to use them inside since this makes grouped conditions easier to write and read. As usual “not” has a higher precedence than “and”, which has higher precedence then “or”:

Operator

Math

Meaning

||

\(\lor\)

(non-exclusive) Or

&&

\(\land\)

And

!

\(\neg\)

Negation

Example: Both of the following expression evaluate to true, if A is not 1 and between 10 and 20, i.e. \( \neg (A=1) \land ( A \ge 10 \lor A \le 20)\):

[[ ! $A -eq 1 && ( $A -ge 10 || $A -le 20 ) ]]
! [[ $A -ne 1 ]] && ( [[ $A -ge 10 ]] || [[ $A -le 20 ]] )