Shell in a nutshell - Testing, Looping and Branching
Image source
- Reference
I referred to Chapter 3 from “Pro Bash Programming Scripting the GNU/Linux Shell” written by Christ F.A. Johnson. Please read this book if you would like to get more information. You can get this book from this site. - Exercise script. (Chapter 3)
I wrote an exercise script and you can download it from this link.
What is looping and branching in bash?
Looping is very frequently used in the programming languages. It runs iteratively and passes the arguments to the next command line. There are three types of loop such as for, while, and until. Branching refers to conditional executions such as if and case because these executions have a type of programming flow that traverses a tree. It sounds pretty reasonable because conditional execution evaluates a given condition and then chooses the branch if the condition is acceptable.
Testing arguments and variables.
There are two things you should know for testing an expression: “[[ ” , ” ]]”, and “(( ” , ” ))”. You can choose square brackets for normal tasks like comparing strings, numerous file attributes, and regular expression. For testing arithmetic expressions, you can use parentheses. However, notice that these expressions are non-standard method but “test” command itself is standard method. (I prefer non-standard method.)
1. File test
The state of files or folders can be tested by following commands. If you want the opposite effect of following commands then simply add “!” symbol between the beginning of square bracket and -option. For example, [[ ! -f /tmp/test.txt ]].
# True if a test.txt file is a regular file.
test -f /tmp/test.txt # Using test command.
[[ -f /tmp/test.txt ]] # Using square bracket which initiates a same task above.
# True if a test.txt file exists and has contents.
[[ -e /tmp/test.txt ]]
# True if test is a directory.
[[ -d /tmp/test ]]
# True if a test.txt file is readable.
[[ -r /tmp/test.txt ]]
# True if a test.txt file is writable.
[[ -w /tmp/test.txt ]]
# True if a test.txt file exists and executable.
[[ -x /tmp/test.txt ]]
2. Integer test# Test integer 1 is equal to 1.
test 1 -eq 1
# Test integer 2 is not equal to 1.
[[ 2 -ne 1 ]]
3. String testTo compare two strings, “=” or “==” operators are used in bash. If you want to check the equality of strings then type “==”, but for inequality type “!=”.
a="test string"
b="string test"
# Test two strings are different.
[[ "$a" != "$b" ]]
# Other options are also available.
# True if the length of string is 0.
[[ -z "" ]]
# True if the length of string is not 0.
[[ -n "string" ]]
When the greater-than (“<”) and less-than (“>”) symbols are used in bash to compare two strings then “\” symbol needs to be marked before them to prevent these operators from being interpreted as redirection operators. In bash, “>” symbol is being used for saving printed strings as a text file and you don’t want this result when you compare two strings.# Compare two strings.
test "abc" \< "abcd"
# Check whether a regular file exists and (-a) the value of test argument is equal to 1.
test -f /tmp/test.txt -a $test -eq 1
# Check whether a regular file is executable or (-o) the value of test argument is greater than 1.
test -x /tmp/test.txt -o $test -gt 1
Another feature from square bracket (“[[ … ]]”) symbols is regular expression by typing “=~” operator. This is only applicable in bash.string=flower
# Match $string with regular expression "l[aeiou]".
[[ $string =~ l[aeiou] ]]
4. Arithmetic evaluationWhen it comes to arithmetic calculation, bash is not friendly for this kind of task. However, there are still possible ways to deal with mathematical calculation in bash by using parentheses (“(( … ))”).
# Add and multiply three numbers and check whether it is not 0.
test $(( 3 + 5 * 8)) -ne 0
After testing the values in parentheses, you can determine whether next job should be processed or not. For example, you can evaluate a value and proceed next step if the value is non zero.# Test a value and proceed the job if it is non zero
(( $value )) && echo "The value is not zero."
Just like “-a” (and), “-o” (or) options, “&&” and “||” symbols execute same operation in the parentheses respectively.Conditional execution
Conditional statements examines the given statement and selects one that meets the condition and executes following command lines.
1. If statement
If statement examines the given statement and selects one that meets the condition and executes a block of lines.
# The basic syntax of if statement.
if <condition list>
then
<list>
fi
Let’s check out for 3 real examples.- Read and check input.
# Get input from the user.
read name
# test the length of string is zero or non zero.
if [[ -z $name ]]; then
# Print message if the string is empty.
# >&2 means do not print error message.
echo "No name entered" >&2
# Set a failed return code.
exit 1
fi
- Prompt for a number and check that it is not greater than 10.
# Get the input from the user.
printf "Engter a number not greater than 10: "
read number
# Test the given number.
if (( $number > 10 )); then
# Inform that the number is too large.
printf "%d is too big\n" "$number" >&2
exit 1
# Run this line if the first condition is not met.
else
# Print the given number.
printf "You entered %d\n" "$number"
fi
- Prompt for a number and check that it is within a given range.
printf "Enter a number between 10 and 20 inclusive: "
read number
if (( $number < 10 )); then
printf "%d is too low\n" "$number" > &2
exit 1
# Run this line if the first condition is not met
elif (( $number > 20)); then
printf "%d is too high\n" "$number" >&2
exit 1
# Run this line if the first and second conditions are not met.
else
printf "You entered %d\n" "$number"
fi
Instead of using if statement, “&&” and “||” symbols which called conditional operators can also be used and sometimes it simplifies the code.# Check the $directory exists and if it is true, get into the directory.
test -d "$directory" && cd "$directory"
# Change directory but if it fails exit the code.
cd "tmp/test" || exit 1
# Create a directory. If it is successful then go into that directory or exit the code.
mkdir "tmp/test" && cd "tmp/test" || exit 1
# Two symbols are often used in if statement for adding up more conditions.
if [ -d "$dir" ] && cd "$dir"; then
echo "Print now directory path: $PWD"
fi
2. CaseA case statement check a word or variable with other patterns and executes the commands that related with that pattern.
# The basic syntax of case statement.
case WORD in
# Set one or more pattern lines.
PATTERN1) COMMANDS1 ;;
...
PATTERN2) COMMANDS2 ;;
Let’s check out for 2 real examples.- Does one string contain another?
# Set variables.
test1="my name is hyungwon"
test2="name"
case $test1 in
# If $test1 contains $test2 give true.
*"$test2"*) true ;;
# In case of else give false. "*" refers anything in regular expression.
*) false ;;
esac
- Is this a valid positive integer?
case $1 in
$ If input is not integer give false.
*[!0-9]*) false ;;
$ In case of else give true.
*) true ;;
esac
Looping
When you have to open many files or execute same commands to a number of files iteratively, loop is needed to handle that kind of tasks.
1. While
While loop checks the given statement and runs a block of code repeatedly until the statement fails.
while <list>; do
<commands>
done
Let’s check out for 3 real examples.- Run repeatedly if $n is smaller than 10.
n=0
while [[ $n -le 10 ]]; do
echo "$n"
n=$(( $n+1 ))
done
- True command for creating an infinite loop. Press Control + x in order to break the while loop.
while true; do
# keep reading the inputs from the user.
read x
done
- Read line by line from a file.
while IFS= read -r line; do
echo "$line"
done < test.txt
2. UntilI have never used this loop before, but bash provides this loop. it is the opposite of while. I will show you a brief example of until loop.
n=1
until [[ $n -gt 10 ]]; do
echo "$n"
n=$(( $n+1 ))
done
3. ForFor loop is the most frequently used in the bash script. Let’s look at the two examples. One is iteratively passing down the strings or variables, the other one is increasing numbers and passing each number down to the next code lines.
- Strings
# Get the strings one by one and print them.
for var in Canada USA Mexico
printf "%s\n" "$var"
done
- Numbers
# Increase the number one by one and print them.
for (( n=1; n<=10; ++n )); do
echo "$n"
done
# Since the number is increasing sequentially, you can use other simple syntax.
for $(seq 1 10); do
echo "$n"
done
# There is another way to handle a same task.
for {1..10}; do
echo "$n"
done
4. BreakThis command breaks any loops in the middle of execution.
- In one while loop.
# Read the input from the user and break the while loop if the user gives the zero length string.
while true; do
read x
[[ -z "$x" ]] && break
done
- In two for and while loops.
for n in a b c d e; do
# $RANDOM will automatically generate random numbers.
if [[ $RANDOM -gt 20000 ]]; then
printf .
# Break both for and while loops by designating a number 2.
break 2
elif [[ $RANDOM -lt 10000 ]]; then
printf '"'
# Break out of the while loop but not for loop.
break
fi
done
5. ContinueThe “continue” command immediately initiates next iteration if it located inside of a loop, by ignoring left commands. Let’s see its usage with simple example.
for n in {1..9}; do
x=$RANDOM
[[ $x -le 20000 ]] && continue
echo "n=$n x=$x"
done
Hyungwon Yang
댓글
댓글 쓰기