(M)  s i s t e m a   o p e r a c i o n a l   m a g n u x   l i n u x ~/ · documentação · suporte · sobre

 

3.8. Loops

A loop is a block of code that iterates (repeats) a list of commands as long as the loop control condition is true.

for (in)

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

Note: Each [list] element may contain multiple parameters. This is useful when processing parameters in groups. In such cases, use the set command (see Example 3-40) to force parsing of each [list] element and assignment of each component to the positional parameters.

Example 3-27. for loop with two parameters in each [list] element

#!/bin/bash
# Planets revisited.

# Want to associate name of each planet with its distance from the sun.

for planet in "Mercury 36" "Venus 67" "Earth 93"  "Mars 142" "Jupiter 483"
do
  set $planet  # Parses variable "planet" and sets positional parameters.
  # May need to save original positional parameters, since they get overwritten.
  echo "$1		$2,000,000 miles from the sun"
  #-------two  tabs---concatenate zeroes onto parameter $2
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-28. 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-29. 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
while

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 (see Section 3.9).

Example 3-30. 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-31. Another while loop

#!/bin/bash

echo

while [ "$var1" != end ]
do
  echo "Input variable #1 (end to exit) "
  read var1
  # It's not 'read $var1' because value of var1 is being set.
  echo "variable #1 = $var1"
  # Need quotes because of #
  echo
done  

# Note: Echoes 'end' because termination condition tested for at top of loop.

exit 0

Note: A while loop may have multiple conditions. Only the final condition determines when the loop terminates. This necessitates a slightly different loop syntax, however.

Example 3-32. while loop with multiple conditions

#!/bin/bash

var1=unset
previous=$var1

while echo "previous-variable = $previous"
      echo
      previous=$var1
      [ "$var1" != end ] # Keeps track of what "var1" was previously.
      # Four conditions on "while", but only last one controls loop.
      # Controlling condition has [ test ] brackets.
do
echo "Input variable #1 (end to exit) "
  read var1
  echo "variable #1 = $var1"
done  

# Try to figure out how this all works.
# It's a wee bit tricky.

exit 0

Note: A while loop may have its stdin redirected to a file by a < at its end (see Example 3-73).

until

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

Example 3-33. until loop

#!/bin/bash

until [ "$var1" = end ]
# Tests condition at top of loop.
do
  echo "Input variable #1 "
  echo "(end to exit)"
  read var1
  echo "variable #1 = $var1"
done  

exit 0
break, continue

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-34. 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
case (in) / esac

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-35. 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-36. 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 "[S]mith, 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
select

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-37. 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-38. 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