|
|
< Day Day Up > |
|
12.6. Looping CommandsThe looping commands are used to execute a command or group of commands a set number of times, or until a certain condition is met. The Korn shell has four types of loops: for, while, until, and select. 12.6.1 The for CommandThe for looping command is used to execute commands for each member of a set of arguments. 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 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 wordlist
do
command(s)
done
Example 12.29.(The Script) 1 for pal in Tom Dick Harry Joe 2 do 3 print "Hi $pal" 4 done 5 print "Out of loop" (The Output) Hi Tom Hi Dick Hi Harry Hi Joe Out of loop EXPLANATION
Example 12.30.
(The Command Line)
1 $ cat mylist
tom
patty
ann
jake
(The Script)
2 for person in $(< mylist) #same as for person in `cat mylist`
do
3 mail $person < letter
print $person was sent a letter.
4 done
5 print "The letter has been sent."
EXPLANATION
Example 12.31.1 for file in *.c 2 do if [[ -f $file ]] ; then cc $file -o ${file%.c} fi done EXPLANATION
12.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 12.32.
(The Script)
#!/bin/ksh
1 for name in $* # or 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
12.6.3 The while CommandThe while 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. If the exit status never becomes nonzero, the loop goes around and around infinitely. (Of course, pressing Ctrl-C or Ctrl-\ will stop the looping.) FORMAT
while command
do
command(s)
done
Example 12.33.(The Script) 1 num=0 # Initialize num 2 while (( num < 10 )) # Test num with the let do print -n $num 3 (( num=num + 1 )) # Increment num done print "\nAfter loop exits, continue running here" (The Output) 0123456789 After loop exits, continue running here EXPLANATION
Example 12.34.
(The Script)
#!/bin/ksh
# Scriptname: quiz
1 read answer?"Who was the U.S. President in 1992? "
2 while [[ $answer != "Bush" ]]
3 do
print "Wrong try again!"
4 read answer
5 done
6 print Good guess!
(The Output)
$ quiz
Who was the U.S. President in 1992? George
Wrong try again!
Who was the U.S. President in 1992? I give up
Wrong try again!
Who was the U.S. President in 1992? Bush
Good guess!
EXPLANATION
Example 12.35.(The Script) 1 go=1 print Type q to quit. 2 while let go or (( go )) do print I love you. read word 3 if [[ $word = [qQ]* ]] then print "I'll always love you" 4 go=0 fi 5 done (The Output) $ sayit Type q to quit. I love you. I love you. I love you. I love you. I love you. q I'll always love you $ EXPLANATION
12.6.4 The until CommandThe until command is used like the while command, but evaluates the exit status in the opposite way. The until evaluates the command immediately following it, and if its exit status is not 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 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, program execution starts after the done keyword. FORMAT
until command
do
command(s)
done
Example 12.36.
#!/bin/ksh
1 until who | grep linda
2 do
sleep 5
3 done
talk linda@dragonwings
EXPLANATION
Example 12.37.
#!/bin/ksh
1 hour=0
2 until (( hour > 23 ))
do
3 case "$hour" in
[0-9]|1[0-1]) print "Good morning!"
;;
12) print "Lunch time"
;;
1[3-7]) print "Siesta time"
;;
*) print "Good night"
;;
esac
4 (( hour+=1 ))
5 done
EXPLANATION
12.6.5 The select Command and MenusThe here document is an easy method for creating menus, but the Korn shell introduces a new loop, called the select loop, which is used primarily for creating menus. A menu of numerically listed items is displayed to standard error. The PS3 prompt is used to prompt the user for input; by default, PS3 is #?. After the PS3 prompt is displayed, the shell waits for user input. The input should be one of the numbers in the menu list. The input is stored in the special Korn shell REPLY variable. The number in the REPLY variable is associated with the string to the right of the parentheses in the list of selections.[2]
The case command is used with the select command to allow the user to make a selection from the menu and, based on that selection, execute commands. The LINES and COLUMNS variables can be used to determine the layout of the menu items displayed on the terminal. The output is displayed to standard error, each item preceded by a number and closing parenthesis, and the PS3 prompt is displayed at the bottom of the menu. Because the select command is a looping command, it is important to remember to use either the break command to get out of the loop, or the exit command to exit the script. FORMAT
select var in wordlist
do
command(s)
done
Example 12.38.
(The Script)
#!/bin/ksh
# Program name: goodboys
1 PS3="Please choose one of the three boys : "
2 select choice in tom dan guy
3 do
4 case $choice in
tom)
print Tom is a cool dude!
5 break;; # break out of the select loop
6 dan | guy )
print Dan and Guy are both sweethearts.
break;;
*)
7 print " $REPLY is not one of your choices" 1>&2
print "Try again."
;;
8 esac
9 done
(The Command Line)
$ goodboys
1) tom
2) dan
3) guy
Please choose one of the three boys : 2
Dan and Guy are both sweethearts.
$ goodboys
1) tom
2) dan
3) guy
Please choose one of the three boys : 4
4 is not one of your choices
Try again.
Please choose one of the three boys : 1
Tom is a cool dude!
$
EXPLANATION
Example 12.39.
(The Script)
#!/bin/ksh
# Program name: ttype
# Purpose: set the terminal type
# Author: Andy Admin
1 COLUMNS=60
2 LINES=1
3 PS3="Please enter the terminal type: "
4 select choice in wyse50 vt200 vt100 sun
do
5 case $REPLY in
1)
6 export TERM=$choice
print "TERM=$choice"
break;; # break out of the select loop
2 | 3 )
export TERM=$choice
print "TERM=$choice"
break;;
4)
export TERM=$choice
print "TERM=$choice"
break;;
*)
7 print "$REPLY is not a valid choice. Try again" 1>&2
;;
esac
8 done
(The Command Line)
$ ttype
1) wyse50 2) vt200 3) vt100 4) sun
Please enter the terminal type : 4
TERM=sun
$ ttype
1) wyse50 2) vt200 3) vt100 4) sun
Please enter the terminal type : 3
TERM=vt100
$ ttype
1) wyse50 2) vt200 3) vt100 4) sun
Please enter the terminal type : 7
7 is not a valid choice. Try again.
Please enter the terminal type: 2
TERM=vt200
EXPLANATION
12.6.6 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 Korn shell provides loop control commands to control loops. 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 while loops when iterating through a list of positional parameters. FORMAT shift [n] Example 12.40.
(Without a Loop)
(The Script)
#!/bin/ksh
# Scriptname: doit0
1 set joe mary tom sam
2 shift
3 print $*
4 set $(date)
5 print $*
6 shift 5
7 print $*
8 shift 2
(The Output)
$ doit0
3 mary tom sam
5 Sun Sep 9 10:00:12 PDT 2004
7 2004
8 ksh: shift: bad number
EXPLANATION
Example 12.41.
(With a Loop)
(The Script)
#!/bin/ksh
# Usage: doit [args]
1 while (( $# > 0 ))
do
2 print $*
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
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 exit out of any number of outer loops. The break is useful for exiting from an infinite loop. FORMAT break [n] Example 12.42.1 while true; do 2 read answer? Are you ready to move on\? 3 if [[ $answer = [Yy]* ]]; then EXPLANATION
The continue CommandThe continue command starts back at the top of the loop if some condition becomes true. All commands below the continue will be ignored. The continue command returns control to the top of the innermost loop; if nested within a number of loops, the continue command may take a number as its argument. Control can be started at the top of any number of outer loops. FORMAT continue [n] Example 12.43.(The Mailing List) $ cat mail_list ernie john richard melanie greg robin (The Script) # Scriptname: mailtomaillist #!/bin/ksh EXPLANATION
12.6.7 Nested Loops and Loop ControlIf using nested loops, the break and continue commands let you control which loop to terminate. Example 12.44.
(The Script)
#!/bin/ksh
EXPLANATION
12.6.8 I/O Redirection and LoopsThe Korn shell allows you to use redirection and pipes in loops. Unlike the Bourne shell, the loop runs in this shell, not a subshell. Variables set within the loop will still be set when the loop exits. Redirecting the Output of a Loop to a FileInstead of sending the output of a loop to the screen, it can be redirected to a file or a pipe. See Example 12.45. Example 12.45.(The Command Line) 1 $ cat memo abc def ghi ------------------------------------------------------------------ (The Script) #!/bin/ksh # Program name: numberit # Put line numbers on all lines of memo 2 if (( $# < 1 )) then print "Usage: $0 filename " >&2 exit 1 fi 3 integer count=1 # Initialize count 4 cat $1 | while read line # Input is coming from memo do 5 (( count == 1 )) && print "Processing file $1..." > /dev/tty 6 print $count $line 7 (( count+=1 )) 8 done > tmp$$ # Output is going to a temporary file 9 mv tmp$$ $1 (The Command Line) 10 $ numberit memo Processing file memo... 11 $ cat memo 1 abc 2 def 3 ghi EXPLANATION
Piping the Output of a Loop to a UNIX CommandThe output of a loop can be redirected from the screen to a pipe. See Example 12.46. Example 12.46.
(The Script)
1 for i in 7 9 2 3 4 5
2 do
print $i
3 done | sort –n
(The Output)
2
3
4
5
7
9
EXPLANATION
12.6.9 Running Loops in the BackgroundIf the loop is going to take a while to process, it can be run as a background job so that the rest of the program can continue. Example 12.47.
1 for person in bob jim joe sam
do
2 mail $person < memo
3 done &
EXPLANATION
12.6.10 The exec Command and LoopsThe exec command can be used to close standard input or output without creating a subshell. Example 12.48.
(The File)
1 cat tmp
apples
pears
bananas
peaches
plums
-----------------------------------------------------------
(The Script)
#!/bin/ksh
# 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 print $line
5 print –n "Is this word correct? [Y/N] "
6 read answer < /dev/tty # Read from the terminal
case $answer in
[Yy]*)
continue
;;
*)
print "New word? "
7 read word < /dev/tty
sed "s/$line/$word/" tmp > error
mv error tmp
8 print $word has been changed.
;;
esac
done
EXPLANATION
12.6.11 The IFS and LoopsThe IFS, the shell's internal field separator, 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, for, and select. It can be reset by the user if a different separator will be used in a list. It is a good idea to save the original value of the IFS in another variable before changing it. Then it is easy to return to its default value. Example 12.49.
(The Script)
#!/bin/ksh
# 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 print 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
print Howdy $girl
done
(The Output)
$ runit
Hi Tom
Hi Dick
Hi Harry
Hi John
Howdy Jill
Howdy Jane
Howdy Jolene
EXPLANATION
|
|
|
< Day Day Up > |
|