|
|
< Day Day Up > |
|
14.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 bash shell has three types of loops: for, while, and until. 14.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 14.32.
(The Script)
#!/bin/bash
# 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)
Hi Tom
Hi Dick
Hi Harry
Hi Joe
Out of loop
EXPLANATION
Example 14.33.(The Command Line) 1 $ cat mylist tom patty ann jake (The Script) #!/bin/bash # Scriptname: mailer 2 for person in $(cat mylist) # `cat mylist` command substitution the alternate way do 3 mail $person < letter echo $person was sent a letter. 4 done 5 echo "The letter has been sent." EXPLANATION
Example 14.34.
(The Script)
#!/bin/bash
# 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
4 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
14.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 14.35.
(The Script)
#!/bin/bash
# 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 14.36.
(The Script)
#!/bin/bash
# Scriptname: permx
1 for file # Empty wordlist
do
2 if [[ -f $file && ! -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
14.6.3 The while CommandThe while command evaluates the command 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 14.37.
(The Script)
#!/bin/bash
# Scriptname: num
1 num=0 # Initialize num
2 while (( $num < 10 ))[a] # or while [ num -lt 10 ]
do
echo -n "$num "
3 let num+=1 # Increment num
done
4 echo -e "\nAfter loop exits, continue running here"
(The Output)
0 1 2 3 4 5 6 7 8 9
4 After loop exits, continue running here
EXPLANATION
Example 14.38.
(The Script)
#!/bin/bash
# Scriptname: quiz
1 echo "Who was the 2nd U.S. president to be impeached?"
read answer
2 while [[ "$answer" != "Bill Clinton" ]]
3 do
echo "Wrong try again!"
4 read answer
5 done
6 echo You got it!
(The Output)
Who was the 2nd U.S. president to be impeached? Ronald Reagan
Wrong try again!
Who was the 2nd U.S. president to be impeached? I give up
Wrong try again!
Who was the 2nd U.S. president to be impeached? Bill Clinton
You got it!
EXPLANATION
Example 14.39.(The Script) $ cat sayit #!/bin/bash # 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 == [Qq] ]] then # [ "$word" = q -o "$word" = Q ] Old style echo "I'll always love you!" go= fi done (The Output) Type q to quit. I love you. <-- When user presses Enter, the program continues I love you. I love you. I love you. I love you.q I'll always love you! $ EXPLANATION
14.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 14.40.
#!/bin/bash
1 until who | grep linda
2 do
sleep 5
3 done
talk linda@dragonwings
EXPLANATION
Example 14.41.
(The Script)
#!/bin/bash
# Scriptname: hour
1 hour=0
2 until (( hour > 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+=1 )) # Don't forget to increment the hour
5 done
(The Output)
Good morning!
Good morning!
...
Lunch time.
Siesta time.
...
Good night.
...
EXPLANATION
14.6.5 The select Command and MenusThe here document is an easy method for creating menus, but bash introduces another looping mechanism, called the select loop, 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 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. 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. (These variables are built into versions of bash 2.x, but are not built into earlier versions; if they have not been defined, you can define and export them in the .bash_profile.) 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 14.42.
(The Script)
#!/bin/bash
# Scriptname: runit
1 PS3="Select a program to execute: "
2 select program in 'ls -F' pwd date
3 do
4 $program
5 done
(The Command Line)
Select a program to execute: 2
1) ls -F
2) pwd
3) date
/home/ellie
Select a program to execute: 1
1) ls -F
2) pwd
3) date
12abcrty abc12 doit* progs/ xyz
Select a program to execute: 3
1) ls -F
2) pwd
3) date
Sun Mar 12 13:28:25 PST 2004
EXPLANATION
Example 14.43.
(The Script)
#!/bin/bash
# Scriptname: goodboys
1 PS3="Please choose one of the three boys : "
2 select choice in tom dan guy
3 do
4 case "$choice" in
tom)
echo Tom is a cool dude!
5 break;; # break out of the select loop
6 dan | guy )
echo Dan and Guy are both wonderful.
break;;
*)
7 echo "$REPLY is not one of your choices" 1>&2
echo "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 wonderful.
$ 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 14.44.
(The Script)
#!/bin/bash
# Scriptname: 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 xterm sun
do
5 case "$REPLY" in
1)
6 export TERM=$choice
echo "TERM=$choice"
break;; # break out of the select loop
2 | 3 )
export TERM=$choice
echo "TERM=$choice"
break;;
4)
export TERM=$choice
echo "TERM=$choice"
break;;
*)
7 echo -e "$REPLY is not a valid choice. Try again\n" 1>&2
8 REPLY= # Causes the menu to be redisplayed
;;
esac
9 done
(The Command Line)
$ ttype
1) wyse50 2) vt200 3) xterm 4) sun
Please enter the terminal type : 4
TERM=sun
$ ttype
1) wyse50 2) vt200 3) xterm 4) sun
Please enter the terminal type : 3
TERM=xterm
$ ttype
1) wyse50 2) vt200 3) xterm 4) sun
Please enter the terminal type : 7
7 is not a valid choice. Try again.
1) wyse50 2) vt200 3) xterm 4) sun
Please enter the terminal type:
TERM=vt200
EXPLANATION
14.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 bash 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 14.45.
(Without a Loop)
(The Script)
#!/bin/bash
# Scriptname: shifter
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 Thu Mar 18 10:00:12 PST 2004
7 2001
8 shift: shift count must be <= $#
EXPLANATION
Example 14.46.
(With a Loop)
(The Script)
#!/bin/bash
# Name: doit
# Purpose: shift through command-line arguments
# Usage: doit [args]
1 while (( $# > 0 ))
do
2 echo $*
3 shift
4 done
(The Command Line and Output)
$ doit a b c d e
a b c d e
b c d e
c d e
d e
e
EXPLANATION
Example 14.47.
(The Script)
#!/bin/bash
# Scriptname: dater
# Purpose: set positional parameters with the set command
# and shift through the parameters.
1 set $(date)
2 while (( $# > 0 ))
do
3 echo $1
4 shift
done
(The Output)
Wed
Mar
17
19:25:00
PST
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 14.48.#!/bin/bash # Scriptname: loopbreak 1 while true; do 2 echo Are you ready to move on\? read answer 3 if [[ "$answer" == [Yy] ]] 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.[4]
FORMAT continue [n] Example 14.49.
(The mailing List)
$ cat mail_list
ernie
john
richard
melanie
greg
robin
(The Script)
#!/bin/bash
# Scriptname: mailem
# Purpose: To send a list
EXPLANATION
Nested Loops and Loop ControlWhen you are 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 14.50.
(The Script)
#!/bin/bash
# Scriptname: months
EXPLANATION
14.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 FileOutput from a bash loop can be sent to a file rather than to the screen. See Example 14.51. Example 14.51.(The Command Line) 1 $ cat memo abc def ghi (The Script) #!/bin/bash # Program name: numberit # Put line numbers on all lines of memo 2 if (( $# < 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 provided at command line do 6 ((count == 1)) && echo "Processing file $1..." > /dev/tty 7 echo -e "$count\t$line" 8 let 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
Piping the Output of a Loop to a UNIX/Linux CommandOutput can be either piped to another command(s) or redirected to a file. Example 14.52.
(The Script)
#!/bin/bash
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
14.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 14.53.
(The Script)
#!/bin/bash
1 for person in bob jim joe sam
do
2 mail $person < memo
3 done &
EXPLANATION
14.6.9 The 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 14.54.
(The Script )
#/bin/bash
# Scriptname: runit2
# 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 > |
|