REPETITIVE TASKS & VARIABLES
5.1. FOR loop
How does it work?
The for loop is the first of the three shell looping constructs. This loop allows for specification of a list of values. A list of commands is executed for each value in the list.
The syntax for this loop is:
for NAME [in LIST]; do COMMANDS; done
The return status is the exit status of the last command that executes. If no commands are executed because LIST does not expand to any items, the return status is zero.
NAME can be any variable name, although i is used very often. LIST can be any list of words, strings or numbers, which can be literal or generated by any command. The COMMANDS to execute can also be any operating system commands, script, program or shell statement. The first time through the loop, NAME is set to the first item in LIST. The second time, its value is set to the second item in the list, and so on. The loop terminates when NAME has taken on each of the values from LIST and no items are left in LIST.
Activity:
o Using command substitution for specifying LIST items
touch file1.txt file2.txt file3.txt
echo file1.txt > index
echo file2.txt >> index
echo file3.txt >> index
for i in `cat index`
do
cp “$i” “$i”.bak
done
o Using for loop for fixed number of iterations.
for i in {1..5}
do
echo $i
done
for (( i=1; i<=5; i++ ))
do
echo $i
done
5.2. WHILE loop
What is it?
The while construct allows for repetitive execution of a list of commands, as long as the command controlling the while loop executes successfully (exit status of zero). The syntax is:
while CONTROL-COMMAND; do CONSEQUENT-COMMANDS; done
CONTROL-COMMAND can be any command(s) that can exit with a success or failure status. The
CONSEQUENT-COMMANDS can be any program, script or shell construct.
As soon as the CONTROL-COMMAND fails, the loop exits. In a script, the command following the done statement is executed.
The return status is the exit status of the last CONSEQUENT-COMMANDS command, or zero if none was executed.
Activity:
o Simple example using while.
#!/bin/bash
echo “This script will create 4 blank files”
i=”0″
while [ $i -lt 4 ]
do
touch file$i.txt
i=$[$i+1]
done
for i in {0..3}
do
touch file$i.txt
done
o Nested while loops
#!/bin/bash
# This script copies files from my scripting into the backup directory.
# A new directory is created every hour. SCRIPTDIR=/home/oracle/scripting
BACKUPDIR=/home/oracle/backup
while true; do
DATE=`date +%Y%m%d`
HOUR=`date +%H`
mkdir $BACKUPDIR/”$DATE”
while [ $HOUR -ne “00” ]; do
DESTDIR=$BACKUPDIR/”$DATE”/”$HOUR”
mkdir -p “$DESTDIR”
cp $SCRIPTDIR/* “$DESTDIR”/
sleep 3600
HOUR=`date +%H`
done
done
o Using keyboard input to control the while loop
vi /home/oracle/scripting/infra
#!/bin/bash
echo “Received your input as $1”
chmod +x /home/oracle/scripting/infra
#!/bin/bash
# This script runs the executable INFRA=/home/oracle/scripting/infra
while true; do
echo “On which topic do you want advice?”
cat << LIST
Oracle
AWS
SQL Server
AWS RDS
Certifications
LIST
echo
echo -n “Make your choice: “
read topic
echo
echo “Free or Paid advice on the topic of $topic: “
echo
$INFRA $topic
echo
done
o Calculating an average
#!/bin/bash
# Calculate the average of a series of numbers.
SCORE=”0″
AVERAGE=”0″
SUM=”0″
NUM=”0″
while true; do
echo -n “Enter your score [0-1000] (‘q’ for quit): “; read SCORE;
echo -n “Enter your number of attempts : “; read NUM;
if ((“$SCORE” < “0”)) || ((“$SCORE” > “1000”)); then
echo “Be serious. Common, try again: “
elif [ “$SCORE” == “q” ]; then
echo “Average rating: $AVERAGE%.”
break
else
SUM=$SCORE
AVERAGE=$[$SUM / $NUM]
echo “Your average is : $AVERAGE”
break
fi
done
echo “Exiting.”
5.3. UNTIL loop
What is it?
The until loop is very similar to the while loop, except that the loop executes until the TEST-COMMAND executes successfully. As long as this command fails, the loop continues. The syntax is the same as for the while loop:
until TEST-COMMAND; do CONSEQUENT-COMMANDS; done
The return status is the exit status of the last command executed in the CONSEQUENT-COMMANDS list, or zero if none was executed. TEST-COMMAND can, again, be any command that can exit with a success or failure status, and CONSEQUENT-COMMANDS can be any UNIX command, script or shell construct.
As we already explained previously, the “;” may be replaced with one or more newlines wherever it appears.
Activity:
o Simple example using UNTIL.
#!/bin/bash
# This script copies files from my homedirectory into the webserver directory.
# A new directory is created every hour.
# If the logs are taking up too much space, the oldest are removed.
SCRIPTDIR=/home/oracle/scripting
BACKUPDIR=/home/oracle/backup
while true; do
DISKFUL=$(df -h $BACKUPDIR | grep -v File | awk ‘{print $5 }’ | cut -d “%” -f1 -)
until [ $DISKFUL -ge “90” ]; do
DATE=`date +%Y%m%d`
HOUR=`date +%H`
mkdir $BACKUPDIR/”$DATE”
while [ $HOUR -ne “00” ]; do
DESTDIR=$BACKUPDIR/”$DATE”/”$HOUR”
mkdir “$DESTDIR”
mv $SCRIPTDIR/*.jpg “$DESTDIR”/
sleep 3600
HOUR=`date +%H`
done
DISKFULL=$(df -h $BACKUPDIR | grep -v File | awk ‘{ print $5 }’ | cut -d “%” -f1 -)
done
TOREMOVE=$(find $BACKUPDIR -type d -a -mtime +30)
for i in $TOREMOVE; do
rm -rf “$i”;
done
done
5.4. I/O redirection
Input redirection
Instead of controlling a loop by testing the result of a command or by user input, you can specify a file from which to read input that controls the loop. In such cases, read is often the controlling command. As long as input lines are fed into the loop, execution of the loop commands continues. As soon as all the input lines are read the loop exits.
Since the loop construct is considered to be one command structure (such as while TEST-COMMAND; do CONSEQUENT-COMMANDS; done), the redirection should occur after the done statement, so that it complies with the form
command < file
This kind of redirection also works with other kinds of loops.
Output redirection
echo TEST > file.txt
echo TEST >> file.txt
5.5. Break and continue
The break built-in
The break statement is used to exit the current loop before its normal ending. This is done when you don’t know in advance how many times the loop will have to execute, for instance because it is dependent on user input.
Activity:
o Simple example using break.
#!/bin/bash
# This script provides list of Trainings or Certifications
# You can now exit in a decent way. INFRA=/home/oracle/scripting/infra
while true; do
echo
echo “On which topic do you want advice?”
echo “1. Oracle”
echo “2. AWS”
echo “3. SQL Server”
echo “4. AWS RDS”
echo “5. Certifications”
echo
echo -n “Enter your choice, or 0 for exit: “
read choice
echo
case $choice in
1)
$INFRA Oracle
;;
2)
$INFRA AWS
;;
3)
$INFRA SQL Server
;;
4)
$INFRA AWS RDS
;;
5)
$INFRA Certifications
;;
0)
echo “OK, see you!”
break
;;
*)
echo “That is not a valid choice, try a number from to 5.”
;;
esac
done
The continue built-in
The continue statement resumes iteration of an enclosing for, while, until or select loop.
When used in a for loop, the controlling variable takes on the value of the next element in the list. When used in a while or until construct, on the other hand, execution resumes with TEST-COMMAND at the top of the loop.
Activity:
o Example to show how continue works in a loop.
touch test1.log teST2.log teSt3.log
#!/bin/bash
# This script converts all file names containing upper case characters into file# names containing only lower cases.
for name in `ls te*.log`; do
if [[ “$name” != *[[:upper:]]* ]]; then
continue
fi
ORIG=”$name”
NEW=`echo $name | tr ‘A-Z’ ‘a-z’`
mv “$ORIG” “$NEW”
echo “new name for $ORIG is $NEW”
done
5.6. Menu making
General
Use of select
The select construct allows easy menu generation. The syntax is quite similar to that of the for loop:
select WORD [in LIST]; do RESPECTIVE-COMMANDS; done
LIST is expanded, generating a list of items. The expansion is printed to standard error; each item is preceded by a number. If in LIST is not present, the positional parameters are printed, as if in $@ would have been specified. LIST is only printed once.
Upon printing all the items, the PS3 prompt is printed and one line from standard input is read. If this line consists of a number corresponding to one of the items, the value of WORD is set to the name of that item. If the line is empty, the items and the PS3 prompt are displayed again. If an EOF (End Of File) character is read, the loop exits. Since most users don’t have a clue which key combination is used for the EOF sequence, it is more user-friendly to have a break command as one of the items. Any other value of the read line will set WORD to be a null string.
The read line is saved in the REPLY variable.
The RESPECTIVE-COMMANDS are executed after each selection until the number representing the break is read. This exits the loop.
Activity:
o Example to create a simple menu.
#!/bin/bash
echo “This script can make any of the files in this directory private.”
echo “Enter the number of the file you want to protect:”
select FILENAME in *;
do
echo “You picked $FILENAME ($REPLY), it is now only accessible to you.”
chmod 700 “$FILENAME”
done
o Improved menu experience than above.
#!/bin/bash
echo “This script can make any of the files in this directory private.”
echo “Enter the number of the file you want to protect:”
PS3=”Your choice in file number: “
QUIT=”QUIT THIS PROGRAM.”
touch “$QUIT”
select FILENAME in *;
do
case $FILENAME in
“$QUIT”)
echo “Exiting.”
break
;;
*)
echo “You picked $FILENAME ($REPLY)”
chmod 700 “$FILENAME”
;;
esac
done
rm “$QUIT”
5.7. Variables
General assignment of values
As we already saw, Bash understands many different kinds of variables or parameters. Thus far, we haven’t bothered much with what kind of variables we assigned, so our variables could hold any value that we assigned to them.
Activity:
VARIABLE=14
echo $VARIABLE
VARIABLE=character
echo $VARIABLE
There are cases when you want to avoid this kind of behavior, for instance when handling telephone and other numbers. Apart from integers and variables, you may also want to specify a variable that is a constant. This is often done at the beginning of a script, when the value of the constant is declared. After that, there are only references to the constant variable name, so that when the constant needs to be changed, it only has to be done once. A variable may also be a series of variables of any type, a so-called array of variables (VAR0VAR1, VAR2, … VARN).
Using the declare built-in
Using a declare statement, we can limit the value assignment to variables.
The syntax for declare is the following:
declare OPTION(s) VARIABLE=value
The following options are used to determine the type of data the variable can hold and to assign it attributes:
Options to the declare built-in
Option Meaning
-a Variable is an array.
-f Use function names only.
-i The variable is to be treated as an integer; arithmetic evaluation is performed when the variable is assigned a value.
-p Display the attributes and values of each variable. When -p is used, additional options are ignored.
-r Make variables read-only. These variables cannot then be assigned values by subsequent assignment statements, nor can they be unset.
-t Give each variable the trace attribute.
-x Mark each variable for export to subsequent commands via the environment.
Activity:
declare -i VARIABLE=14
VARIABLE=character
echo $VARIABLE
declare -p VARIABLE
Constants
In Bash, constants are created by making a variable read-only. The readonly built-in marks each specified variable as unchangeable. The syntax is:
readonly OPTION VARIABLE(s)
The values of these variables can then no longer be changed by subsequent assignment. If the -f option is given, each variable refers to a shell function; see Chapter 11, Functions. If -a is specified, each variable refers to an array of variables.
If no arguments are given, or if -p is supplied, a list of all read-only variables is displayed. Using the -p option, the output can be reused as input.
The return status is zero, unless an invalid option was specified, one of the variables or functions does not exist, or -f was supplied for a variable name instead of for a function name.
readonly INFRA=Train&Certify
INFRA=Travel
5.8. Operations on variables
Activity:
o Example to find Length of a variable.
echo $SHELL
echo ${#SHELL}
o Example to substitute.
${VAR:-WORD}
If VAR is not defined or null, the expansion of WORD is substituted; otherwise the value of VAR is substituted:
export INFRA=” You can reach out to us from our website given in descripton”
echo ${INFRA:-infra}
echo ${INFRA2:-infra}
o Removing substrings
To strip a number of characters, equal to OFFSET, from a variable, use this syntax:
${VAR:OFFSET:LENGTH}
The LENGTH parameter defines how many characters to keep, starting from the first character after the offset point. If LENGTH is omitted, the remainder of the variable content is taken.
export STRING=”thisisaverylongname”
echo ${STRING:4}
echo ${STRING:6:5}
o Replacing parts of variable names. This is done using the
${VAR/PATTERN/STRING}
or
${VAR//PATTERN/STRING}
syntax. The first form replaces only the first match, the second replaces all matches of PATTERN with STRING
echo ${STRING/name/string}
To continue with Tutorial 6, please click here
To start reading from Chapter 1, please click here