|
|
< Day Day Up > |
|
8.6. Looping CommandsLooping commands are used to execute a command or group of commands a set number of times or until a certain condition is met. The Bourne shell has three types of loops: for, while, and until. 8.6.1 The for CommandThe for looping command is used to execute commands a finite number of times on a list of items. For example, you might use this loop to execute the same commands on a list of files or usernames. The for command is followed by a user-defined variable, the keyword in, and a list of words. The first time in the loop, the first word from the wordlist is assigned to the variable, and then shifted off the list. Once the word is assigned to the variable, the body of the loop is entered, and commands between the do and done keywords are executed. The next time around the loop, the second word is assigned to the variable, and so on. The body of the loop starts at the do keyword and ends at the done keyword. When all of the words in the list have been shifted off, the loop ends and program control continues after the done keyword. FORMAT for variable in word_list do command(s) done Example 8.25.(The Script) #!/bin/sh # Scriptname: forloop 1 for pal in Tom Dick Harry Joe 2 do 3 echo "Hi $pal" 4 done 5 echo "Out of loop" (The Output) $ forloop Hi Tom Hi Dick Hi Harry Hi Joe Out of loop EXPLANATION
Example 8.26.(The Command Line) 1 $ cat mylist tom patty ann jake (The Script) #!/bin/sh # Scriptname: mailer 2 for person in `cat mylist` do 3 mail $person < letter echo $person was sent a letter. 4 done 5 echo "The letter has been sent." EXPLANATION
Example 8.27.
(The Script)
#!/bin/sh
# Scriptname: backup
# Purpose:
# Create backup files and store them in a backup directory
1 dir=/home/jody/ellie/backupscripts
2 for file in memo[1-5]
do
3 if [ -f $file ]
then
cp $file $dir/$file.bak
echo "$file is backed up in $dir"
fi
done
(The Output)
memo1 is backed up in /home/jody/ellie/backupscripts
memo2 is backed up in /home/jody/ellie/backupscripts
memo3 is backed up in /home/jody/ellie/backupscripts
memo4 is backed up in /home/jody/ellie/backupscripts
memo5 is backed up in /home/jody/ellie/backupscripts
EXPLANATION
8.6.2 The $* and $@ Variables in WordlistsWhen expanded, the $* and $@ are the same unless enclosed in double quotes. $* evaluates to one string, whereas $@ evaluates to a list of separate words. Example 8.28.
(The Script)
#!/bin/sh
# Scriptname: greet
1 for name in $* # Same as for name in $@
2 do
echo Hi $name
3 done
(The Command Line)
$ greet Dee Bert Lizzy Tommy
Hi Dee
Hi Bert
Hi Lizzy
Hi Tommy
EXPLANATION
Example 8.29.
(The Script)
#!/bin/sh
# Scriptname:permx
1 for file # Empty wordlist
do
2 if [ -f $file -a ! -x $file ]
then
3 chmod +x $file
echo $file now has execute permission
fi
done
(The Command Line)
4 $ permx *
addon now has execute permission
checkon now has execute permission
doit now has execute permission
EXPLANATION
8.6.3 The while CommandThe while command evaluates the command immediately following it and, if its exit status is 0, the commands in the body of the loop (commands between do and done) are executed. When the done keyword is reached, control is returned to the top of the loop and the while command checks the exit status of the command again. Until the exit status of the command being evaluated by the while becomes nonzero, the loop continues. When the exit status reaches nonzero, program execution starts after the done keyword. FORMAT
while command
do
command(s)
done
Example 8.30.
(The Script)
#!/bin/sh
# Scriptname: num
1 num=0 # Initialize num
2 while [ $num -lt 10 ] # Test num with test command
do
echo -n $num
3 num=`expr $num + 1` # Increment num
done
echo "\nAfter loop exits, continue running here"
(The Output)
0123456789
After loop exits, continue running here
EXPLANATION
Example 8.31.
(The Script)
#!/bin/sh
# Scriptname: quiz
1 echo "Who was the chief defense lawyer in the OJ case?"
read answer
2 while [ "$answer" != "Johnny" ]
3 do
4 echo "Wrong try again!"
read answer
5 done
6 echo You got it!
(The Output)
$ quiz
Who was the chief defense lawyer in the OJ case? Marcia
Wrong try again!
Who was the chief defense lawyer in the OJ case? I give up
Wrong try again!
Who was the chief defense lawyer in the OJ case? Johnny
You got it!
EXPLANATION
Example 8.32.
(The Script)
#!/bin/sh
# Scriptname: sayit
echo Type q to quit.
go=start
1 while [ -n "$go" ] # Make sure to double quote the variable
do
2 echo -n I love you.
3 read word
4 if [ "$word" = q -o "$word" = Q ]
then
echo "I'll always love you!"
go=
fi
done
(The Output)
$ sayit
Type q to quit.
I love you. <- When user presses the Enter key, the program continues
I love you.
I love you.
I love you.
I love you.q
I'll always love you!
$
EXPLANATION
8.6.4 The until CommandThe until command is used like the while command, but executes the loop statements only if the command after until fails; that is, if the command returns an exit status of nonzero. When the done keyword is reached, control is returned to the top of the loop and the until command checks the exit status of the command again. Until the exit status of the command being evaluated by until becomes 0, the loop continues. When the exit status reaches 0, the loop exits, and program execution starts after the done keyword. FORMAT
until command
do
command(s)
done
Example 8.33.
(The Script)
#!/bin/sh
1 until who | grep linda
2 do
sleep 5
3 done
talk linda@dragonwings
EXPLANATION
Example 8.34.
(The Script)
#!/bin/sh
# Scriptname: hour
1 hour=1
2 until [ $hour -gt 24 ]
do
3 case "$hour" in
[0-9] |1[0-1]) echo "Good morning!"
;;
12) echo "Lunch time."
;;
1[3-7]) echo "Siesta time."
;;
*) echo "Good night."
;;
esac
4 hour=`expr $hour + 1`
5 done
(The Output)
$ hour
Good morning!
Good morning!
...
Lunch time
Siesta time
...
Good night.
...
EXPLANATION
8.6.5 Looping Control CommandsIf some condition occurs, you may want to break out of a loop, return to the top of the loop, or provide a way to stop an infinite loop. The Bourne shell provides loop control commands to handle these kinds of situations. The shift CommandThe shift command shifts the parameter list to the left a specified number of times. The shift command without an argument shifts the parameter list once to the left. Once the list is shifted, the parameter is removed permanently. Often, the shift command is used in a while loop when iterating through a list of positional parameters. FORMAT shift [n] Example 8.35.
(Without a loop)
(The Script)
#!/bin/sh
1 set joe mary tom sam
2 shift
3 echo $*
4 set `date`
5 echo $*
6 shift 5
7 echo $*
8 shift 2
(The Output)
3 mary tom sam
5 Fri Sep 9 10:00:12 PDT 2004
7 2004
8 cannot shift
EXPLANATION
Example 8.36.
(With a loop)
(The Script)
#!/bin/sh
# Name: doit
# Purpose: shift through command-line arguments
# Usage: doit [args]
1 while [ $# -gt 0 ]
do
2 echo $*
3 shift
4 done
(The Command Line)
$ doit a b c d e
a b c d e
b c d e
c d e
d e
e
EXPLANATION
Example 8.37.
(The Script)
#!/bin/sh
# Scriptname: dater
# Purpose: set positional parameters with the set command
# and shift through the parameters.
1 set `date`
2 while [ $# -gt 0 ]
do
3 echo $1
4 shift
done
(The Output)
$ dater
Sat
Oct
16
12:12:13
PDT
2004
EXPLANATION
The break CommandThe built-in break command is used to force immediate exit from a loop, but not from a program. (To leave a program, the exit command is used.) After the break command is executed, control starts after the done keyword. The break command causes an exit from the innermost loop, so if you have nested loops, the break command takes a number as an argument, allowing you to break out of a specific outer loop. If you are nested in three loops, the outermost loop is loop number 3, the next nested loop is loop number 2, and the innermost nested loop is loop number 1. The break is useful for exiting from an infinite loop. FORMAT break [n] Example 8.38.
#!/bin/sh
1 while true; do
2 echo Are you ready to move on\?
read answer
3 if [ "$answer" = Y -o "$answer" = y ]
then
EXPLANATION
The continue CommandThe continue command returns control to the top of the loop if some condition becomes true. All commands below the continue will be ignored. If nested within a number of loops, the continue command returns control to the innermost loop. If a number is given as its argument, control can then be started at the top of any loop. If you are nested in three loops, the outermost loop is loop number 3, the next nested loop is loop number 2, and the innermost nested loop is loop number 1.[3]
FORMAT continue [n] Example 8.39.(The mailing List) $ cat mail_list ernie john richard melanie greg robin (The Script) #!/bin/sh # Scriptname: mailem # Purpose: To send a list EXPLANATION
8.6.6 Nested Loops and Loop ControlWhen using nested loops, the break and continue commands can be given a numeric, integer argument so that control can go from the inner loop to an outer loop. Example 8.40.
(The Script)
#!/bin/sh
# Scriptname: months
EXPLANATION
8.6.7 I/O Redirection and SubshellsInput can be piped or redirected to a loop from a file. Output can also be piped or redirected to a file from a loop. The shell starts a subshell to handle I/O redirection and pipes. Any variables defined within the loop will not be known to the rest of the script when the loop terminates. Redirecting the Output of a Loop to a FileSee Example 8.41 for a demonstration of how to redirect the output of a loop to a file. Example 8.41.(The Command Line) 1 $ cat memo abc def ghi (The Script) #!/bin/sh # Program name: numberit # Put line numbers on all lines of memo 2 if [ $# -lt 1 ] then 3 echo "Usage: $0 filename " >&2 exit 1 fi 4 count=1 # Initialize count 5 cat $1 | while read line # Input is coming from file on command line do 6 [ $count -eq 1 ] && echo "Processing file $1..." > /dev/tty 7 echo $count $line 8 count=`expr $count + 1` 9 done > tmp$$ # Output is going to a temporary file 10 mv tmp$$ $1 (The Command Line) 11 $ numberit memo Processing file memo... 12 $ cat memo 1 abc 2 def 3 ghi EXPLANATION
Example 8.42.(The Input File) $ cat testing apples pears peaches (The Script) #!/bin/sh # This program demonstrates the scope of variables when # assigned within loops where the looping command uses # redirection. A subshell is started when the loop uses # redirection, making all variables created within the loop # local to the shell where the loop is being executed. 1 while read line do 2 echo $line # This line will be redirected to outfile 3 name=JOE 4 done < testing > outfile # Redirection of input and output 5 echo Hi there $name (The Output) 5 Hi there EXPLANATION
Piping the Output of a Loop to a UNIX CommandOutput can be either piped to another command(s) or redirected to a file. Example 8.43.
(The Script)
#!/bin/sh
1 for i in 7 9 2 3 4 5
2 do
echo $i
3 done | sort –n
(The Output)
2
3
4
5
7
9
EXPLANATION
8.6.8 Running Loops in the BackgroundLoops can be executed to run in the background. The program can continue without waiting for the loop to finish processing. Example 8.44.
(The Script)
#!/bin/sh
1 for person in bob jim joe sam
do
2 mail $person < memo
3 done &
EXPLANATION
8.6.9 The exec Command and LoopsThe exec command can be used to open or close standard input or output without creating a subshell. Therefore, when starting a loop, any variables created within the body of the loop will remain when the loop completes. When using redirection in loops, any variables created within the loop are lost. The exec command is often used to open files for reading and writing, either by name or by file descriptor number. Recall that file descriptors 0, 1, and 2 are reserved for standard input, output, and error. If a file is opened, it will receive the next available file descriptor. For example, if file descriptor 3 is the next free descriptor, the new file will be assigned file descriptor 3. Example 8.45.(The File) 1 $ cat tmp apples pears bananas pleaches plums (The Script) #!/bin/sh # Scriptname: speller # Purpose: Check and fix spelling errors in a file 2 exec < tmp # Opens the tmp file 3 while read line # Read from the tmp file do 4 echo $line 5 echo –n "Is this word correct? [Y/N] " 6 read answer < /dev/tty # Read from the terminal 7 case "$answer" in 8 [Yy]*) 9 continue;; *) echo "What is the correct spelling? " 10 read word < /dev/tty 11 sed "s/$line/$word/g" tmp > error 12 mv error tmp 13 echo $line has been changed to $word. esac 14 done EXPLANATION
8.6.10 IFS and LoopsThe shell's internal field separator (IFS) evaluates to spaces, tabs, and the newline character. It is used as a word (token) separator for commands that parse lists of words, such as read, set, and for. It can be reset by the user if a different separator will be used in a list. Before changing its value, it is a good idea to save the original value of the IFS in another variable. Then it is easy to return to its default value, if needed. Example 8.46.
(The Script )
#/bin/sh
# Scriptname: runit
# IFS is the internal field separator and defaults to
# spaces, tabs, and newlines.
# In this script it is changed to a colon.
1 names=Tom:Dick:Harry:John
2 OLDIFS="$IFS" # Save the original value of IFS
3 IFS=":"
4 for persons in $names
do
5 echo Hi $persons
done
6 IFS="$OLDIFS" # Reset the IFS to old value
7 set Jill Jane Jolene # Set positional parameters
8 for girl in $*
do
9 echo Howdy $girl
done
(The Output)
5 Hi Tom
Hi Dick
Hi Harry
Hi John
9 Howdy Jill
Howdy Jane
Howdy Jolene
EXPLANATION
|
|
|
< Day Day Up > |
|