Sams Teach Yourself Shell Programming in 24 Hours
(Publisher: Macmillan Computer Publishing)
Author(s): Sriranga Veeraraghavan
ISBN: 0672314819
Publication Date: 01/01/99

Previous Table of Contents Next


An Example of the select Loop

One common use of the select loop is in scripts that configure software. The following example is a simplified version of one such script. The actual configuration commands have been omitted because they are not relevant in this discussion.

select COMPONENT in comp1 comp2 comp3 all none
do
    case $COMPONENT in
        comp1|comp2|comp3) CompConf $COMPONENT ;;
        all) CompConf comp1
             CompConf comp2
             CompConf comp3
             ;;
        none) break ;;
        *) echo "ERROR: Invalid selection, $REPLY." ;;
    esac
done

The menu presented by the select loop looks like the following:

1) comp1
2) comp2
3) comp3
4) all
5) none
#?

Here you see that each of the items in the list

comp1 comp2 comp3 all none

are displayed with a number preceding them. The user can enter one of these numbers to select a particular component.

If a valid selection is made, the select loop executes a case statement contained in its body. This case statement performs the correct action based on the user’s input. Here the correct action is either calling a command named CompConf, exiting the loop, or displaying an error message.

Changing the Prompt

You can change the prompt displayed by the select loop by altering the variable PS3. If PS3 is not set, the default prompt, #?, is displayed. Otherwise the value of PS3 is used as the prompt to display. For example, the commands

$ PS3="Please make a selection => " ; export PS3

change the menu displayed in the previous example to the following:

1) comp1
2) comp2
3) comp3
4) all
5) none
Please make a selection =>

Notice that the value of PS3 that you used has a space as its last character so that user input does not run into the prompt. You do this in order to make the menu user-friendly.

Loop Control

So far you have looked at creating loops and working with loops to accomplish different tasks. Sometimes you need to stop a loop or skip iterations of the loop. In this section you’ll look at the commands used to control loops:

  break
  continue

Infinite Loops and the break Command

When you looked at the while loop earlier in this chapter, it terminated when a particular condition was met. This happened when the task of the while loop completed.

If you make a mistake in specifying the termination condition of a while loop, it can continue forever. For example, say you forgot to specify the $ before the x in the test expression:

x=0
while [ x -lt 10 ]
do
    echo $x
     x=`echo "$x + 1" | bc`
done


This loop would continue to display numbers forever. A loop that executes forever without terminating executes an infinite number of times. For this reason, such loops are called infinite loops.

In most cases infinite looping is not desired and stems from programming errors, but in certain instances they can be useful. For example, say that you need to wait for a particular event, such as someone logging on to a system, to occur.

You can use an infinite loop to check every few seconds whether the event has occurred. Because you don’t know how many times you need to execute the loop, when the event occurs, you can exit the infinite loop using the break command.

In sh, you can create infinite loops using the while loop. Because a while loop executes list while command is true, specifying command as either : or /bin/true causes the loop to execute forever.

The basic syntax of the infinite while loop is

while :
do
    list
done

In most infinite loops, the while loop usually exits from within list via the break command, which enables you to exit any loop immediately.

Consider the following interactive script that reads and executes commands:

while :
do
    read CMD
    case $CMD in
        [qQ]|[qQ][uU][iI][tT]) break ;;
        *) process $CMD ;;
     esac
done

In this loop you read a command at the beginning of each iteration. If that command is either q or Quit, the loop exits; otherwise, the loop tries to process the command.

Breaking Out of Nested Loops

The break command also accepts as an argument an integer, greater or equal to 1, indicating the number of levels to break out of. This feature is useful when nested loops are being used. Consider the following nested for loops:

for i in 1 2 3 4 5
do
    mkdir –p /mnt/backup/docs/ch0${i}
    if [ $? –eq 0 ] ; then
        for j in doc c h m pl sh
        do
            cp $HOME/docs/ch0${i}/*.${j} /mnt/backup/docs/ch0${i}
            if [ $? –ne 0 ] ; then break 2 ; fi
        done
    else
        echo "Could not make backup directory."
    fi
done

In this loop, I’m making a backup of several important files from my home directory to the backup directory. The outer loop takes care of creating the backup directory, whereas the inner loop copies the important files based on the extension.

In the inner loop, you have a break command with the argument 2. This indicates that if an error occurs while copying you should break out of both loops, and not just the inner loop.

The continue Command

The continue command is similar to the break command, except that it causes the current iteration of the loop to exit, rather than the entire loop. This command is useful when an error has occurred but you want to try to execute the next iteration of the loop.

As an example, the following loop doesn’t exit if one of the input files is bad:

for FILE in $FILES ;
do
    if [ ! –f "$FILE" ] ; then
        echo "ERROR: $FILE is not a file."
        continue
    fi
    # process the file
done

If one of the filenames in $FILES is not a file, this loop skips it, rather than exiting.


Previous Table of Contents Next