RSS Feed Share on Twitter

Buy this Shell Scripting Tutorial as a PDF for only $5

7. Loops

Most languages have the concept of loops: If we want to repeat a task twenty times, we don't want to have to type in the code twenty times, with maybe a slight change each time.
As a result, we have for and while loops in the Bourne shell. This is somewhat fewer features than other languages, but nobody claimed that shell programming has the power of C.

For Loops

for loops iterate through a set of values until the list is exhausted:
for i in 1 2 3 4 5
  echo "Looping ... number $i"

Try this code and see what it does. Note that the values can be anything at all:
for i in hello 1 * 2 goodbye 
  echo "Looping ... i is set to $i"

This is well worth trying. Make sure that you understand what is happening here. Try it without the * and grasp the idea, then re-read the Wildcards section and try it again with the * in place. Try it also in different directories, and with the * surrounded by double quotes, and try it preceded by a backslash (*)

In case you don't have access to a shell at the moment (it is very useful to have a shell to hand whilst reading this tutorial), the results of the above two scripts are:

Looping .... number 1
Looping .... number 2
Looping .... number 3
Looping .... number 4
Looping .... number 5

and, for the second example:

Looping ... i is set to hello
Looping ... i is set to 1
Looping ... i is set to (name of first file in current directory)
    ... etc ...
Looping ... i is set to (name of last file in current directory)
Looping ... i is set to 2
Looping ... i is set to goodbye

So, as you can see, for simply loops through whatever input it is given, until it runs out of input.

While Loops

while loops can be much more fun! (depending on your idea of fun, and how often you get out of the house... )
while [ "$INPUT_STRING" != "bye" ]
  echo "Please type something in (bye to quit)"
  echo "You typed: $INPUT_STRING"

What happens here, is that the echo and read statements will run indefinitely until you type "bye" when prompted.
Review Variables - Part I to see why we set INPUT_STRING=hello before testing it. This makes it a repeat loop, not a traditional while loop.

The colon (:) always evaluates to true; whilst using this can be necessary sometimes, it is often preferable to use a real exit condition. Compare quitting the above loop with the one below; see which is the more elegant. Also think of some situations in which each one would be more useful than the other:
while :
  echo "Please type something in (^C to quit)"
  echo "You typed: $INPUT_STRING"

Another useful trick is the while read loop. This example uses the case statement, which we'll cover later. It reads from the file myfile.txt, and for each line, tells you what language it thinks is being used.

(note: Each line must end with a LF (newline) - if cat myfile.txt doesn't end with a blank line, that final line will not be processed.)

This reads the file "myfile.txt", one line at a time, into the variable "$input_text". The case statement then checks the value of $input_text. If the word that was read from myfile.txt was "hello" then it echoes the word "English". If it was "gday" then it will echo Australian. If the word (or words) read from a line of myfile.txt don't match any of the provided patterns, then the catch-all "*" default will display the message "Unknown Language: $input_text" - where of course "$input_text" is the value of the line that it read in from myfile.txt.
while read input_text
  case $input_text in
        hello)          echo English    ;;
        howdy)          echo American   ;;
        gday)           echo Australian ;;
        bonjour)        echo French     ;;
        "guten tag")    echo German     ;;
        *)              echo Unknown Language: $input_text
done < myfile.txt

Let's say our myfile.txt file contains the following five lines:

this file is called myfile.txt and we are using it as an example input.

A sample run of this script would go like this:

$ ./
Unknown Language: this file is called myfile.txt and we are using it as an example input.
Unknown Language: hola

A handy Bash (but not Bourne Shell) tip I learned recently from the Linux From Scratch project is:

mkdir rc{0,1,2,3,4,5,6,S}.d

instead of the more cumbersome:

for runlevel in 0 1 2 3 4 5 6 S
  mkdir rc${runlevel}.d

And this can be done recursively, too:

$ cd /
$ ls -ld {,usr,usr/local}/{bin,sbin,lib}
drwxr-xr-x    2 root     root         4096 Oct 26 01:00 /bin
drwxr-xr-x    6 root     root         4096 Jan 16 17:09 /lib
drwxr-xr-x    2 root     root         4096 Oct 27 00:02 /sbin
drwxr-xr-x    2 root     root        40960 Jan 16 19:35 usr/bin
drwxr-xr-x   83 root     root        49152 Jan 16 17:23 usr/lib
drwxr-xr-x    2 root     root         4096 Jan 16 22:22 usr/local/bin
drwxr-xr-x    3 root     root         4096 Jan 16 19:17 usr/local/lib
drwxr-xr-x    2 root     root         4096 Dec 28 00:44 usr/local/sbin
drwxr-xr-x    2 root     root         8192 Dec 27 02:10 usr/sbin

We will use while loops further in the Test and Case sections.

RSS Feed Share on Twitter
Back: Escape Characters Next: Test



Books and eBooks


You can mail me with this form. If you expect a reply, please ensure that the address you specify is valid. Don't forget to include the simple addition question at the end of the form, to prove that you are a real person!

You can buy the content of this Shell Scripting Tutorial as a PDF!