| 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 |