Advanced Bash-Scripting HOWTO: A guide to shell scripting, using Bash | ||
---|---|---|
Prev | Chapter 3. Tutorial / Reference | Next |
This is the basic looping construct. It differs significantly from its C counterpart.
for [arg] in [list]
do
command...
done
Note that list may contain wild cards.
Note further that if do is on same line as for, there needs to be a semicolon before list.
for [arg] in [list] ; do
Example 3-24. Simple for loops
#!/bin/bash for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto do echo $planet done echo # Entire 'list' enclosed in quotes creates a single variable. for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto" do echo $planet done exit 0 |
Omitting the in [list] part of a for loop causes the loop to operate on $#, the list of arguments given on the command line to the script.
Example 3-25. Missing in [list] in a for loop
#!/bin/bash # Invoke both with and without arguments, # and see what happens. for a do echo $a done # 'in list' missing, therefore # operates on '$#' # (command-line argument list) exit 0 |
Example 3-26. Using efax in batch mode
#!/bin/bash if [ $# -ne 2 ] # Check for proper no. of command line args. then echo "Usage: `basename $0` phone# text-file" exit 1 fi if [ ! -f $2 ] then echo "File $2 is not a text file" exit 2 fi # Create fax formatted files from text files. fax make $2 for file in $(ls $2.0*) # Concatenate the converted files. # Uses wild card in variable list. do fil="$fil $file" done # Do the work. efax -d /dev/ttyS3 -o1 -t "T$1" $fil exit 0 |
This construct tests for a condition at the top of a loop, and keeps looping as long as that condition is true.
while [condition]
do
command...
done
As is the case with for/in loops, placing the do on the same line as the condition test requires a semicolon.
while [condition] ; do
Note that certain specialized while loops, as, for example, a getopts construct, deviate somewhat from the standard template given here.
Example 3-27. Simple while loop
#!/bin/bash var0=0 while [ "$var0" -lt 10 ] do echo -n "$var0 " # -n suppresses newline. var0=`expr $var0 + 1` # var0=$(($var0+1)) also works. done echo exit 0 |
Example 3-28. Another while loop
#!/bin/bash while [ "$var1" != end ] do echo "Input variable #1 " echo "(end to exit)" read var1 # It's not 'read $var1' # because value of var1 is set. echo "variable #1 = $var1" # Need quotes because of # done # Note: Echoes 'end' because # termination condition # tested for at top of loop. exit 0 |
This construct tests for a condition at the top of a loop, and keeps looping as long as that condition is false (opposite of while loop).
until [condition-is-true]
do
command...
done
Note that an until loop tests for the terminating condition at the top of the loop, differing from a similar construct in some programming languages.
As is the case with for/in loops, placing the do on the same line as the condition test requires a semicolon.
until [condition-is-true] ; do
The break and continue loop control commands correspond exactly to their counterparts in other programming languages. The break command terminates the loop (breaks out of it), while continue causes a jump to the next iteration of the loop, skipping all the remaining commands in that particular loop cycle.
Example 3-30. Effects of break and continue in a loop
#!/bin/bash echo echo Printing Numbers 1 through 20. a=0 while [ $a -le 19 ] do a=$(($a+1)) if [ $a -eq 3 ] || [ $a -eq 11 ] # Excludes 3 and 11 then continue # Skip rest of this particular loop iteration. fi echo -n "$a " done # Exercise for reader: # Why does loop print up to 20? echo echo echo Printing Numbers 1 through 20, but something happens after 2. ################################################################## # Same loop, but substituting 'break' for 'continue'. a=0 while [ $a -le 19 ] do a=$(($a+1)) if [ $a -gt 2 ] then break # Skip entire rest of loop. fi echo -n "$a " done echo echo exit 0 |
The case construct is the shell equivalent of switch in C/C++. It permits branching to one of a number of code blocks, depending on condition tests. It serves as a kind of shorthand for multiple if/then/else statements and is an appropriate tool for creating menus.
case "$variable" in
"$condition1" )
command...
;;
"$condition2" )
command...
;;
esac
Note:
Quoting the variables is recommended.
Each test line ends with a left paren ).
Each condition block ends with a double semicolon ;;.
The entire case block terminates with an esac (case spelled backwards).
Example 3-31. Using case
#!/bin/bash echo echo "Hit a key, then hit return." read Keypress case "$Keypress" in [a-z] ) echo "Lowercase letter";; [A-Z] ) echo "Uppercase letter";; [0-9] ) echo "Digit";; * ) echo "Punctuation, whitespace, or other";; esac # Allows ranges of characters in [square brackets]. exit 0 |
Example 3-32. Creating menus using case
#!/bin/bash # Crude rolodex-type database clear # Clear the screen. echo " Contact List" echo " ------- ----" echo "Choose one of the following persons:" echo echo "[E]vans, Roland" echo "[J]ones, Mildred" echo "[Smith], Julie" echo "[Z]ane, Morris" echo read person case "$person" in # Note variable is quoted. "E" | "e" ) # Accept upper or lowercase input. echo echo "Roland Evans" echo "4321 Floppy Dr." echo "Hardscrabble, CO 80753" echo "(303) 734-9874" echo "(303) 734-9892 fax" echo "revans@zzy.net" echo "Business partner & old friend" ;; # Note double semicolon to terminate # each option. "J" | "j" ) echo echo "Mildred Jones" echo "249 E. 7th St., Apt. 19" echo "New York, NY 10009" echo "(212) 533-2814" echo "(212) 533-9972 fax" echo "milliej@loisaida.com" echo "Girlfriend" echo "Birthday: Feb. 11" ;; # Add info for Smith & Zane later. * ) # Default option. echo echo "Not yet in database." ;; esac echo exit 0 |
The select construct, adopted from the Korn Shell, is yet another tool for building menus.
select variable [in list]
do
command...
break
done
This prompts the user to enter one of the choices presented in the variable list. Note that select uses the PS3 prompt (#? ) by default, but that this may be changed.
Example 3-33. Creating menus using select
#!/bin/bash PS3='Choose your favorite vegetable: ' # Sets the prompt string. echo select vegetable in "beans" "carrots" "potatoes" "onions" "rutabagas" do echo echo "Your favorite veggie is $vegetable." echo "Yuck!" echo break # if no 'break' here, keeps looping forever. done exit 0 |
If in list is omitted, then select uses the list of command line arguments ($@) passed to the script or to the function in which the select construct is embedded. (Compare this to the behavior of a
for variable [in list]
construct with the in list omitted.)Example 3-34. Creating menus using select in a function
#!/bin/bash PS3='Choose your favorite vegetable: ' echo choice_of() { select vegetable # [in list] omitted, so 'select' uses arguments passed to function. do echo echo "Your favorite veggie is $vegetable." echo "Yuck!" echo break done } choice_of beans rice carrots radishes tomatoes spinach # $1 $2 $3 $4 $5 $6 # passed to choice_of() function exit 0 |