2. More testing constructions
-
The compound command
[[ expression ]]
Modern versions of bash include a compound command that acts as an enhanced replacement for test:
[[ expression ]]
. It has also an operator for regular expression matching:=~
.test-integer2.sh
#!/bin/bash
# test-integer2: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if [ "$INT" -eq 0 ]; then
echo "INT is zero."
else
if [ "$INT" -lt 0 ]; then
echo "INT is negative."
else
echo "INT is positive."
fi
if [ $((INT % 2)) -eq 0 ]; then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fivim test-integer2.sh
./test-integer2.sh
More testing
sed -i test-integer2.sh -e '/^INT=/c INT=11'
./test-integer2.sh
sed -i test-integer2.sh -e '/^INT=/c INT='
./test-integer2.sh
sed -i test-integer2.sh -e '/^INT=/c INT=0'
./test-integer2.sh
sed -i test-integer2.sh -e '/^INT=/c INT=12'
./test-integer2.shAnother added feature of
[[ ]]
is that the==
operator supports pattern matching the same way pathname expansion does:FILE=foo.bar
if [[ $FILE == foo.* ]]; \
then echo "$FILE matches pattern 'foo.*'"; fi -
The compound command
(( integer expression ))
In addition to the compound command
[[ ]]
, bash also provides the compound command(( ))
, which is useful for operating on integers.if ((1)); then echo "It is true."; fi
if ((0)); then echo "It is true."; fi
if ((2)); then echo "It is true."; fi
With this test command we can simplify a bit the previous example script:
test-integer2a.sh
#!/bin/bash
# test-integer2a: evaluate the value of an integer.
INT=-5
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
if ((INT == 0)); then
echo "INT is zero."
else
if ((INT < 0)); then
echo "INT is negative."
else
echo "INT is positive."
fi
if (( ((INT % 2)) == 0)); then
echo "INT is even."
else
echo "INT is odd."
fi
fi
else
echo "INT is not an integer." >&2
exit 1
fivim test-integer2a.sh
./test-integer2a.sh
diff -u test-integer2.sh test-integer2a.sh \
| highlight -S bash -O xterm256 2>/dev/nullNotice that we don't use a
$
sign to refer to variables inside(( ))
. Also, instead of-eq
we use the operator==
, instead of-lt
we use<
, etc. This makes the syntax a bit more natural. -
We can use logical operators to create complex expressions. For the
test
(and[ ]
) command the logical operators are-a
(AND),-o
(OR) and!
(NOT). For the commands[[ ]]
and(( ))
they are:&&
,||
and!
.test-integer3.sh
#!/bin/bash
# test-integer3: determine if an integer is within a
# specified range of values.
MIN_VAL=1
MAX_VAL=100
INT=50
if [[ ! "$INT" =~ ^-?[0-9]+$ ]]; then
echo "INT is not an integer." >&2
exit 1
fi
if [[ "$INT" -ge "$MIN_VAL" && "$INT" -le "$MAX_VAL" ]]; then
echo "$INT is within $MIN_VAL to $MAX_VAL."
else
echo "$INT is out of range."
fi
echo -n "Using [[ ... ]]: "
if [[ ! ("$INT" -ge "$MIN_VAL" && "$INT" -le "$MAX_VAL") ]]; then
echo "$INT is outside $MIN_VAL to $MAX_VAL."
else
echo "$INT is in range."
fi
echo -n "Using (( ... )): "
if (( ! (INT > MIN_VAL && INT < MAX_VAL) )); then
echo "$INT is outside $MIN_VAL to $MAX_VAL."
else
echo "$INT is in range."
fi
echo -n "Using [ ... ] : "
if [ ! \( "$INT" -ge "$MIN_VAL" -a "$INT" -le "$MAX_VAL" \) ];
then
echo "$INT is outside $MIN_VAL to $MAX_VAL."
else
echo "$INT is in range."
fivim test-integer3.sh
./test-integer3.sh
The option
-n
of the commandecho
tells it to not print a newline after the string.Notice that because
test
and[
are treated as commands (unlike[[
and((
which are special shell constructs), each argument given to them has to be separated by a space. Also, the parentheses that group logical expressions have to be escaped like this:\(
and\)
, otherwise shell will interpret them as something else (they have a special meaning in shell).Usually it is more convenient to use
[[
instead oftest
or[
. -
We can use the operators
&&
(AND) and||
(OR) for conditional execution of a command. They can be used like this:command1 && command2
First is executed
command1
. If (and only if) it is successful, thecommand2
is executed as well.command1 || command2
First is executed
command1
. If (and only if) it fails, thecommand2
is executed as well.For example:
mkdir temp && cd temp
[[ -d temp ]] || mkdir temp
The first one is equivalent to:
if mkdir temp; then cd temp; fi
The second one is equivalent to:
if [[ -d temp ]]; then : ; else mkdir temp; fi
The command
:
is a null command, which means "do nothing". Without it we would get a syntax error.