Shell Scripting With Bash For Linux Administration - Part 2
Sep 5, 2018 • 6 Minute Read
Set Up
For additonal context to set up your workspace, please view the first guide in this series User and Group Management in Linux and Shell Scripting With Bash For Linux Administration - Part 1.
Conditional Statements for Shell Scripts
When you need to execute different series of commands depending on a condition, the shell provides a standard if/elif/else construct, similar to most programming languages.
The syntax of a basic conditional statement is shown in pseudo-code as follows. Note that there must be a space after the opening bracket and before the closing one:
if [ condition 1 ]
then
commands
elif [ condition 2 ]
commands
else
commands
fi
The elif section is optional and used only when needed to test for a specific alternative to the condition specified through the if.
Let's use the following example to illustrate:
#!/bin/bash
CURRENTDAYOFTHEMONTH=$(date +%d)
if [ $CURRENTDAYOFTHEMONTH -le 10 ]
then
echo "We are within the first 10 days of the month";
elif [ $CURRENTDAYOFTHEMONTH -le 20 ]
then
echo "We are within the first 20 days of the month";
else
echo "We are within the last 10 days of the month";
fi
The above script returns different messages depending on the current day of the month. The first if tests whether the current day is less or equal to 10. If this condition evaluates to true, the message We are within the first 10 days of the month is displayed and the other conditions are not tested. Otherwise, elif checks if $CURRENTDAYOFTHEMONTH is less than or equal to 20. If that is the case, We are within the first 20 days of the month will be returned instead. If none of the previous conditions are met, the default else block will apply, returning We are within the last 10 days of the month.
Loops
Once in a while, some tasks will need to be executed repeatedly either a fixed number of times or until a specified condition is satisfied. That is where the for and while looping constructs come in handy. Additionally, at times you will need a script to choose between different courses of action based on the value of a given variable - we'll use the case statement for that.
The For Loop
This looping construct is used to operate on each element of a list of known items. Such a list can be specified explicitly (by listing each element one by one) or as the result of a command. The basic syntax of the for loop is illustrated in the following pseudo-code:
for variable-name in list
do
Run command on variable-name as $variable-name
done
variable-name is an arbitrary name that represents an item in list during each iteration.
For example, we can change the permissions on files file1.txt, file2.txt, and file3.txt to 640 using a for loop very easily:
for FILE in file1.txt file2.txt file3.txt
do
chmod 640 $FILE
done
In the above example, the variable named FILE is used inside the loop (between the do and done lines) as $FILE. During the first, second, and third iteration, $FILE represents file1.txt, file2.txt, and file3.txt, respectively.
An alternative approach is to provide the list of files using the ls command and grep to only return the files where the names begin with the word file.
for FILE in $(ls -1 | grep file)
do
chmod 640 $FILE
done
This produces the same result as the previous example.
The While Loop
As opposed to the for loop, while is typically used when the number of iterations is not known beforehand or when using for is impractical. Examples include, but are not limited to, reading a file line by line, increasing or decreasing the value of a variable until it reaches a given value, or responding to user input.
The basic syntax of the while loop is:
while condition is true
do
Run commands here
done
To illustrate, let's consider two examples. First, let's read the /etc/passwd file line by line and return a message showing each username with its corresponding UID. This is an example of the case when we need to repeat an iteration an undetermined number of times.
The UID, or User ID, is an integer number that identifies each user in the third field in /etc/passwd. It can be returned for each individual account using the id command followed by the username.
while read LINE
do
USERNAME=$(echo $LINE | cut -d':' -f 1)
USERID=$(echo $LINE | cut -d':' -f 3)
echo "The UID of $USERNAME is $USERID"
done < /etc/passwd
In this example, the condition that is checked at the beginning of each iteration is whether we have reached the end of the file. The variable named LINE represents each line in /etc/passwd. This file is set as the input to the loop by using the < redirection operator. When each line is read, the contents of the first and third fields are stored in USERNAME and USERID, respectively.
Let's take a look at the output of the while loop, which we have saved in a script named users.sh in the current working directory. The content of the output may vary from system to system depending on the number and names of user accounts.
Finally, let's write a simple number-guessing game in a script called guess.sh. When the script is launched, a random number between 1 and 10 is generated and stored in the variable RANDOMNUM. The script then will expect input from the user and indicate if the guess is correct, less than, or greater than the right number. This will continue until the user guesses the number correctly. In this example, $NUMBER != $RANDOMNUM is enclosed within square brackets to indicate accurately what is the condition to test.
#!/bin/bash
RANDOMNUM=$(shuf -i1-10 -n1)
NUMBER=0
while [ $NUMBER != $RANDOMNUM ]
do
read -p "Enter a number between 1 and 10: " NUMBER
done
echo "Congratulations! Your guess was right!"
The following image shows our game in action: