1. Branching with if
The if statement has the following syntax:
if commands; then
#commands
#...
elif commands; then
#commands
#...
else
#commands
#...
fi
The elif
and else
parts are optional. The elif
part can be
repeated more than once.
-
Commands (including the scripts and shell functions) return an exit status. By convention, an exit status of zero indicates success and any other value indicates failure.
ls -d /usr/bin
echo $?
ls -d /bin/usr
echo $?
The builtin commands
true
andfalse
do nothing except returning an exit status:true
echo $?
false
echo $?
-
The
if
statement evaluates the success or failure of the commands, based on their exit status:if true; then echo "It's true."; fi
if false; then echo "It's true."; fi
If a list of commands follows
if
, the last command in the list is evaluated:if false; true; then echo "It's true."; fi
if true; false; then echo "It's true."; fi
-
The command used most frequently with
if
istest
, which performs a variety of checks and comparisons.touch foo.txt
if test -e foo.txt; then echo "File exists"; fi
if [ -e foo.txt ]; then echo "File exists"; \
else echo "File does not exist"; fiThe command
[
is equivalent totest
(it requires]
as the last argument).rm -f foo.txt
if [ -e foo.txt ]; then echo "File exists"; \
else echo "File does not exist"; fi -
Let's see an example script that is testing files:
test-file.sh
#!/bin/bash
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
exit 1
fi
exitvim test-file.sh
Notice that the parameter
$FILE
is quoted within the expression. This is not required, but it is a defense against the parameter being empty or containing whitespace.Notice also the
exit
command at the end. It can optionally take a number as an argument, which becomes the exit status of the script, indicating success or failure. Without an argument, the default is the exit status of the last command executed. If the commandexit
is not present at all, the exit status of the script will be the exit status of the last command executed../test-file.sh
Edit the script, change the variable
FILE
and execute it again. You can also try to set it to the name of a directory.Let's do some more testing
sed -i test-file.sh \
-e '/^FILE=/c FILE=./test-file.sh'
head test-file.sh
./test-file.shsed -i test-file.sh \
-e '/^FILE=/c FILE=~/examples/'
head test-file.sh
./test-file.shsed -i test-file.sh \
-e '/^FILE=/c FILE="non existent file"'
head test-file.sh
./test-file.sh -
Let's see a similar example that uses a function instead:
test-file-fun.sh
#!/bin/bash
FILE=~/.bashrc
# test-file: Evaluate the status of a file
test_file () {
if [ -e "$FILE" ]; then
if [ -f "$FILE" ]; then
echo "$FILE is a regular file."
fi
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fi
if [ -w "$FILE" ]; then
echo "$FILE is writable."
fi
if [ -x "$FILE" ]; then
echo "$FILE is executable/searchable."
fi
else
echo "$FILE does not exist"
return 1
fi
}
test_filevim test-file-fun.sh
Notice that instead of
exit
, a function can usereturn
to indicate the exit status of the function../test-file-fun.sh
Let's do some more testing
sed -i test-file-fun.sh \
-e '/^FILE=/c FILE=./test-file.sh'
grep '^FILE=' test-file-fun.sh
./test-file-fun.shsed -i test-file-fun.sh \
-e '/^FILE=/c FILE=~/examples/'
grep '^FILE=' test-file-fun.sh
./test-file-fun.shsed -i test-file-fun.sh \
-e '/^FILE=/c FILE="non existent file"'
grep '^FILE=' test-file-fun.sh
./test-file-fun.sh -
An example with testing strings:
test-string.sh
#!/bin/bash
# test-string: evaluate the value of a string
ANSWER=maybe
if [ -z "$ANSWER" ]; then
echo "There is no answer." >&2
exit 1
fi
if [ "$ANSWER" = "yes" ]; then
echo "The answer is YES."
elif [ "$ANSWER" = "no" ]; then
echo "The answer is NO."
elif [ "$ANSWER" = "maybe" ]; then
echo "The answer is MAYBE."
else
echo "The answer is UNKNOWN."
fivim test-string.sh
Notice that when there is an error (
ANSWER
is empty), we print the error message tostderr
by redirecting the output ofecho
(>&2
). We also return an exit code of 1 byexit 1
../test-string.sh
Let's do some more testing
sed -i test-string.sh -e '/^ANSWER=/c ANSWER=yes'
./test-string.sh
sed -i test-string.sh -e '/^ANSWER=/c ANSWER=no'
./test-string.sh
sed -i test-string.sh -e '/^ANSWER=/c ANSWER=xyz'
./test-string.sh
sed -i test-string.sh -e '/^ANSWER=/c ANSWER='
./test-string.sh -
A similar example with testing integers:
test-integer.sh
#!/bin/bash
# test-integer: evaluate the value of an integer.
INT=-5
if [ -z "$INT" ]; then
echo "INT is empty." >&2
exit 1
fi
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
fivim test-integer.sh
./test-integer.sh
Change the number that is assigned to
INT
and execute it again.More testing
sed -i test-integer.sh -e '/^INT=/c INT=11'
./test-integer.sh
sed -i test-integer.sh -e '/^INT=/c INT='
./test-integer.sh
sed -i test-integer.sh -e '/^INT=/c INT=0'
./test-integer.sh
sed -i test-integer.sh -e '/^INT=/c INT=12'
./test-integer.sh -
For more details about the available tests let's see the help:
help test | less
help [
type test
type [