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 users 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.
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 youll look at the commands used to control loops:
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 dont 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, Im 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 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 doesnt 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 |