Introduction Linux
Introduction Linux
Bash loops are very useful. In this section of our Bash Scripting Tutorial we'll look at the different
loop formats available to us as well as discuss when and why you may want to use each of them.
Loops allow us to take a series of commands and keep re-running them until a particular
situation is reached. They are useful for automating repetitive tasks.
There are 3 basic loop structures in Bash scripting which we'll look at below. There are also a
few statements which we can use to control the loops operation.
While Loops
One of the easiest loops to work with is while loops. They say, while an expression is true, keep
executing these lines of code. They have the following format:
You'll notice that similar to if statements the test is placed between square brackets [ ].
while_loop.sh
1. #!/bin/bash
2. # Basic while loop
3.
4. counter=1
5. while [ $counter -le 10 ]
6. do
7. echo $counter
8. ((counter++))
9. done
10.
11. echo All done
Let's break it down:
Line 4 - We'll initialise the variable counter with it's starting value.
Line 5 - While the test is true (counter is less than or equal to 10) let's do the following
commands.
Line 7 - We can place any commands here we like. Here echo is being used as it's an
easy way to illustrate what is going on.
Line 8 - Using the double brackets we can increase the value of counter by 1.
Line 9 - We're at the bottom of the loop so go back to line 5 and perform the test again. If
the test is true then execute the commands. If the test is false then continue executing
any commands following done.
1. ./while_loop.sh
2. 1
3. 2
4. 3
5. 4
6. 5
7. 6
8. 7
9. 8
10. 9
11. 10
12. All done
13.
A common mistake is what's called an off by one error. In the example above we could have put
-lt as opposed to -le (less than as opposed to less than or equal). Had we done this it would have
printed up until 9. These mistakes are easy to make but also easy to fix once you've identified it
so don't worry too much if you make this error.
Until Loops
The until loop is fairly similar to the while loop. The difference is that it will execute the
commands within it until the test becomes true.
until_loop.sh
1. #!/bin/bash
2. # Basic until loop
3.
4. counter=1
5. until [ $counter -gt 10 ]
6. do
7. echo $counter
8. ((counter++))
9. done
10.
11. echo All done
As you can see in the example above, the syntax is almost exactly the same as the while loop
(just replace while with until). We can also create a script that does exactly the same as the while
example above just by changing the test accordingly.
So you may be asking, 'Why bother having the two different kinds of loops?'. We don't
necessarily. The while loop would be able to handle every scenario. Sometimes, however, it just
makes it a little easier to read if we phrase it with until rather than while. Think about the
following statement:
Or:
But they just don't seem as elegant and easy to understand. So by having
both while and until we can pick whichever one makes the most sense to us and as a result,
end up with code that is easier for us to understand when we read it.
We should always strive for clean, obvious and elegant code when writing our Bash scripts.
For Loops
The for loop is a little bit different to the previous two loops. What it does is say for each of the
items in a given list, perform the given set of commands. It has the following syntax.
for_loop.sh
1. #!/bin/bash
2. # Basic for loop
3.
4. names='Stan Kyle Cartman'
5.
6. for name in $names
7. do
8. echo $name
9. done
10.
11. echo All done
1. ./for_loop.sh
2. Stan
3. Kyle
4. Cartman
5. All done
6.
Ranges
We can also process a series of numbers
for_loop_series.sh
1. #!/bin/bash
2. # Basic range in for loop
3.
4. for value in {1..5}
5. do
6. echo $value
7. done
8.
9. echo All done
Line 4 - It's important when specifying a range like this that there are no spaces present
between the curly brackets { }. If there are then it will not be seen as a range but as a list
of items.
1. ./for_loop_series.sh
2. 1
3. 2
4. 3
5. 4
6. 5
7. All done
8.
When specifying a range you may specify any number you like for both the starting value and
ending value. The first value may also be larger than the second in which case it will count down.
It is also possible to specify a value to increase or decrease by each time. You do this by adding
another two dots ( .. ) and the value to step by.
for_loop_stepping.sh
1. #!/bin/bash
2. # Basic range with steps for loop
3.
4. for value in {10..0..2}
5. do
6. echo $value
7. done
8.
9. echo All done
1. ./for_loop.sh
2. 10
3. 8
4. 6
5. 4
6. 2
7. 0
8. All done
9.
One of the more useful applications of for loops is in the processing of a set of files. To do this
we may use wildcards. Let's say we want to convert a series of .html files over to .php files.
convert_html_to_php.sh
1. #!/bin/bash
2. # Make a php copy of any html files
3.
4. for value in $1/*.html
5. do
6. cp $value $1/$( basename -s .html $value ).php
7. done
Break
The break statement tells Bash to leave the loop straight away. It may be that there is a normal
situation that should cause the loop to end but there are also exceptional situations in which it
should end as well. For instance, maybe we are copying files but if the free disk space get's
below a certain level we should stop copying.
copy_files.sh
1. #!/bin/bash
2. # Make a backup set of files
3.
4. for value in $1/*
5. do
6. used=$( df $1 | tail -1 | awk '{ print $5 }' | sed 's/%//' )
7. if [ $used -gt 90 ]
8. then
9. echo Low disk space 1>&2
10. break
11. fi
12. cp $value $1/backup/
13. done
Continue
The continue statement tells Bash to stop running through this iteration of the loop and begin the
next iteration. Sometimes there are circumstances that stop us from going any further. For
instance, maybe we are using the loop to process a series of files but if we happen upon a file
which we don't have the read permission for we should not try to process it.
copy_check.sh
1. #!/bin/bash
2. # Make a backup set of files
3.
4. for value in $1/*
5. do
6. if [ ! -r $value ]
7. then
8. echo $value not readable 1>&2
9. continue
10. fi
11. cp $value $1/backup/
12. done
Select
The select mechanism allows you to create a simple menu system. It has the following format:
When invoked it will take all the items in list (similar to other loops this is a space separated set
of items) and present them on the screen with a number before each item. A prompt will be
printed after this allowing the user to select a number. When they select a number and
hit enter the corresponding item will be assigned to the variable var and the commands between
do and done are run. Once finished a prompt will be displayed again so the user may select
another option.
No error checking is done. If the user enters something other than a number or a number
not corresponding to an item then var becomes null (empty)
If the user hits enter without entering any data then the list of options will be displayed
again.
The loop will end when an EOF signal is entered or the break statement is issued.
You may change the system variable PS3 to change the prompt that is displayed.
select_example.sh
1. #!/bin/bash
2. # A simple menu system
3.
4. names='Kyle Cartman Stan Quit'
5.
6. PS3='Select character: '
7.
8. select name in $names
9. do
10. if [ $name == 'Quit' ]
11. then
12. break
13. fi
14. echo Hello $name
15. done
16.
17. echo Bye
Line 4 - Set up a variable with the list of characters and a last option which we may
select to quit. Note that the items are separated by a space.
Line 6 - Change the value of the system variable PS3 so that the prompt is set to
something a little more descriptive. (By default it is #?)
Lines 10 - 13 - If the last option, 'Quit', is selected then break out of the select loop.
Line 14 - Print out a message just to demonstrate the mechanism has worked. You may
have as many commands here as you like.
Line 17 - Print a message just to show that the script has continued as normal after the
select loop.
Using the for loop in shell scripts is reasonably straightforward, and you can manipulate the structure to achieve different goals.
do
[COMMANDS]
done
for VARIABLE in 1 2 3 4 5 .. N
do
command1
command2
commandN
done
You can define the number of iterations in the first line. This way, you'll mention the starting value and the ending value.
The number of iterations is determined by the values you specify, while the code following the do statement is the resulting
loop value.
for i in 1 2 3
do
done
Where:
i = variable name to store the iterated values
1 2 3 = number of times the for loop in shell script iterates
do = command to perform a certain set of actions
echo = print the results defined alongside
done = end of the loop
2. Alternate Way to Print a Set of
Numbers
There are alternate ways to define a for loop in
a shell script. You can also specify the starting
and ending value of the loop's iterations using
curly brackets.
Here's the code structure:
for i in {1..3} # a for loop defines a variable and how many
iterations you want to make through a loop
do
done
do
done
Where:
i = variable to store the iterations
1..10 = number of iterations to run the loop
2 = step value
do = command to print the output
echo = print command
done = exit command for the loop
do
done
Where:
name = variable to store the string values
do = command to print the output
echo = print command
done = exit command for the loop
break
fi
done