ch6 flow control using loops
Unlike most loops, the for loop does not test the condition of a variable each time it goes
around the loop. Instead, it starts with a list of items to iterate through and works its way
through them until it has reached the end.
#!/bin/bash
for fruit in apple orange pear
do
echo “I really like ${fruit}s”
done
echo “Let’s make a salad!”
--
FOR
cat forin1
#!/bin/bash
for fruit in $*
do
echo "I like $fruit"
done
The for loop is best when you know that you want to do the same thing to a set of items, rather than
wanting to repeat something until a certain state is achieved
for loops are not so good if
you expect that you will want to break out of the loop based on the outcome of some test or other.
$* expands to all of the parameters passed on the command line
$ cat fruit-read.sh
#!/bin/bash
echo -en “Please tell me some of your favorite fruit: “
read fruits
for fruit in $fruits
do
echo “I really like ${fruit}s”
done
echo “Let’s make a salad!”
$ ./fruit-read.sh
Please tell me some of your favorite fruit: kiwi banana grape apple
I really like kiwis
I really like bananas
I really like grapes
I really like apples
Let’s make a salad!
The command-line parameters can be processed in another way; the in list part of the syntax is
optional. It is perfectly valid to run the following script. It processes the $@ variables to work in the
same way as fruit-cmdline.sh.
$ cat for.sh
#!/bin/bash
for fruit
do
echo I really like $fruit
done
echo “Let’s make a salad!”
$ ./for.sh apples oranges bananas
I really like apples
I really like oranges
I really like bananas
Let’s make a salad!
seq is only available on GNUbased
systems, such as Linux, so although it is very useful, do be aware that it is not portable across
many different operating systems.
$ cat ping.sh
#!/bin/bash
UPHOSTS=/var/log/uphosts.`date +%m%d%Y`
DOWNHOSTS=/var/log/downhosts.`date +%m%d%Y`
PREFIX=192.168.1
for OCTET in `seq 1 254`
do
echo -en “Pinging ${PREFIX}.${OCTET}....”
ping -c1 -w1 ${PREFIX}.${OCTET} > /dev/null 2>&1
if [ “$?” -eq “0” ]; then
echo “ OK”
echo “${PREFIX}.${OCTET}” >> ${UPHOSTS}
else
echo “ Failed”
echo “${PREFIX}.${OCTET}” >> ${DOWNHOSTS}
fi
done
$ ./ping.sh
Pinging 192.168.1.1.... OK
Pinging 192.168.1.2.... Failed
Pinging 192.168.1.3.... OK
Pinging 192.168.1.4.... OK
As you can see, the backtick (`) takes the output from the seq command and uses it as input to the
for loop.
---------------------
The end
of the /etc/profile script then calls each one of those scripts in turn. It uses the . command to
source the file, rather than simply executing it, so that any environmental changes are picked up
by the calling shell.
$ for i in /etc/profile.d/*.sh; do
> if [ -r $i ]; then
> . $i
> fi
> done
-----------
While loops - when you cannot predict when the condition that you are looking for will occur
$ cat while.sh
#!/bin/bash
i=1
while [ “$i” -lt “100” ]
do
echo “i is $i”
i=`expr $i \* 2`
done
echo “Finished because i is now $i”
$ ./while.sh
i is 1
i is 2
i is 4
i is 8
i is 16
i is 32
i is 64
Finished because i is now 128
$
----------------------
Mathematical calculations, time comparisons, and the state of items external to the current process are all suitable things for while loops.
---------------------
Another common use for while is to read the contents of a text file, line by line.
--------------------
date | grep
12:15 returns success (return code 0) if the time is 12:15, but not if it is 12:16.
$ while date | grep 12:15
> do
> sleep 5
> done
Tue Dec 28 12:15:48 GMT 2010
Tue Dec 28 12:15:53 GMT 2010
Tue Dec 28 12:15:58 GMT 2010
$
-------------------
$ cat nest.sh
#!/bin/sh
myfruit=””
while [ “$myfruit” != “quit” ]
do
for fruit in apples bananas pears $myfruit
do
echo “I like $fruit”
done # end of the for loop
read -p “What is your favorite fruit? “ myfruit
done # end of the while loop
echo “Okay, bye!”
$ ./nest.sh
I like apples
I like bananas
I like pears
What is your favorite fruit? grapes
I like apples
I like bananas
I like pears
I like grapes
What is your favorite fruit? plums
I like apples
I like bananas
I like pears
I like plums
What is your favorite fruit? quit
Okay, bye!
$
------------
The first recipe shows a typical use of continue; when continue is executed, the rest of the current run
through the loop is omitted, and you go back to the first line again
--------------
$ cat continue-backwards.sh
#!/bin/bash
i=1
while [ “$i” -lt “5” ]; do
echo “i is $i”
read -p “Press r to repeat, any other key to continue: “ x
if [ “$x” == “r” ]; then
echo “Going again...”
continue
fi
let i=$i+1
done
$ ./continue-backwards.sh
i is 1
Press r to repeat, any other key to continue: a
i is 2
Press r to repeat, any other key to continue: r
Going again...
i is 2
Press r to repeat, any other key to continue: b
i is 3
Press r to repeat, any other key to continue: r
Going again...
i is 3
Press r to repeat, any other key to continue: c
i is 4
Press r to repeat, any other key to continue: d
$
----------------------
$ cat while-case.sh
#!/bin/bash
quit=0
while read command data
do
case $command in
echo)
echo “Found an echo command: $data”
;;
upper)
echo -en “Found an upper command: “
echo $data | tr ‘[:lower:]’ ‘[:upper:]’
;;
lower)
echo -en “Found a lower command: “
echo $data | tr ‘[:upper:]’ ‘[:lower:]’
;;
quit)
echo “Quitting as requested.”
quit=1
break
;;
*)
echo “Read $command which is not valid input.”
echo “Valid commands are echo, upper, lower, or quit.”
;;
esac
done
if [ $quit -eq 1 ]; then
echo “Broke out of the loop as directed.”
else
echo “Got to the end of the input without being told to quit.”
fi
$ ./while-case.sh
Hello
Read Hello which is not valid input.
Valid commands are echo, upper, lower, or quit.
echo Hello
Found an echo command: Hello
lower Hello
Found a lower command: hello
upper Hello
Found an upper command: HELLO
quit
Quitting as requested.
Broke out
Ctrl-D (^D) to provide an end-of-file
------------
A very useful tool for menus is called select. It originally comes from the Kornshell, but is also found
in bash.
One interesting aspect of the select loop is that it has no conditional test at all; the only way
out of the loop is to use break or exit
select continuously loops around, displaying a prompt, and
sets its variable to the value provided by the loop
What you can really do with select loops is far more open than that — you can associate absolutely
any action with each option
--------------
Probably the hardest thing when using loops in a script is determining which type of loop to use.
for loops are best at iterating over a predefined list of items; while and until loops are better at
continuing to execute code until some test condition changes. The select loop makes for really
quick and easy menuing systems.
around the loop. Instead, it starts with a list of items to iterate through and works its way
through them until it has reached the end.
#!/bin/bash
for fruit in apple orange pear
do
echo “I really like ${fruit}s”
done
echo “Let’s make a salad!”
--
FOR
cat forin1
#!/bin/bash
for fruit in $*
do
echo "I like $fruit"
done
bash forin1 a b c
I like a
I like b
I like c
----------------
arguments to the function
The for loop is best when you know that you want to do the same thing to a set of items, rather than
wanting to repeat something until a certain state is achieved
for loops are not so good if
you expect that you will want to break out of the loop based on the outcome of some test or other.
$* expands to all of the parameters passed on the command line
$ cat fruit-read.sh
#!/bin/bash
echo -en “Please tell me some of your favorite fruit: “
read fruits
for fruit in $fruits
do
echo “I really like ${fruit}s”
done
echo “Let’s make a salad!”
$ ./fruit-read.sh
Please tell me some of your favorite fruit: kiwi banana grape apple
I really like kiwis
I really like bananas
I really like grapes
I really like apples
Let’s make a salad!
The command-line parameters can be processed in another way; the in list part of the syntax is
optional. It is perfectly valid to run the following script. It processes the $@ variables to work in the
same way as fruit-cmdline.sh.
$ cat for.sh
#!/bin/bash
for fruit
do
echo I really like $fruit
done
echo “Let’s make a salad!”
$ ./for.sh apples oranges bananas
I really like apples
I really like oranges
I really like bananas
Let’s make a salad!
seq is only available on GNUbased
systems, such as Linux, so although it is very useful, do be aware that it is not portable across
many different operating systems.
$ cat ping.sh
#!/bin/bash
UPHOSTS=/var/log/uphosts.`date +%m%d%Y`
DOWNHOSTS=/var/log/downhosts.`date +%m%d%Y`
PREFIX=192.168.1
for OCTET in `seq 1 254`
do
echo -en “Pinging ${PREFIX}.${OCTET}....”
ping -c1 -w1 ${PREFIX}.${OCTET} > /dev/null 2>&1
if [ “$?” -eq “0” ]; then
echo “ OK”
echo “${PREFIX}.${OCTET}” >> ${UPHOSTS}
else
echo “ Failed”
echo “${PREFIX}.${OCTET}” >> ${DOWNHOSTS}
fi
done
$ ./ping.sh
Pinging 192.168.1.1.... OK
Pinging 192.168.1.2.... Failed
Pinging 192.168.1.3.... OK
Pinging 192.168.1.4.... OK
As you can see, the backtick (`) takes the output from the seq command and uses it as input to the
for loop.
---------------------
The end
of the /etc/profile script then calls each one of those scripts in turn. It uses the . command to
source the file, rather than simply executing it, so that any environmental changes are picked up
by the calling shell.
$ for i in /etc/profile.d/*.sh; do
> if [ -r $i ]; then
> . $i
> fi
> done
-----------
While loops - when you cannot predict when the condition that you are looking for will occur
$ cat while.sh
#!/bin/bash
i=1
while [ “$i” -lt “100” ]
do
echo “i is $i”
i=`expr $i \* 2`
done
echo “Finished because i is now $i”
$ ./while.sh
i is 1
i is 2
i is 4
i is 8
i is 16
i is 32
i is 64
Finished because i is now 128
$
----------------------
Mathematical calculations, time comparisons, and the state of items external to the current process are all suitable things for while loops.
---------------------
Another common use for while is to read the contents of a text file, line by line.
--------------------
date | grep
12:15 returns success (return code 0) if the time is 12:15, but not if it is 12:16.
$ while date | grep 12:15
> do
> sleep 5
> done
Tue Dec 28 12:15:48 GMT 2010
Tue Dec 28 12:15:53 GMT 2010
Tue Dec 28 12:15:58 GMT 2010
$
-------------------
$ cat nest.sh
#!/bin/sh
myfruit=””
while [ “$myfruit” != “quit” ]
do
for fruit in apples bananas pears $myfruit
do
echo “I like $fruit”
done # end of the for loop
read -p “What is your favorite fruit? “ myfruit
done # end of the while loop
echo “Okay, bye!”
$ ./nest.sh
I like apples
I like bananas
I like pears
What is your favorite fruit? grapes
I like apples
I like bananas
I like pears
I like grapes
What is your favorite fruit? plums
I like apples
I like bananas
I like pears
I like plums
What is your favorite fruit? quit
Okay, bye!
$
------------
The first recipe shows a typical use of continue; when continue is executed, the rest of the current run
through the loop is omitted, and you go back to the first line again
--------------
$ cat continue-backwards.sh
#!/bin/bash
i=1
while [ “$i” -lt “5” ]; do
echo “i is $i”
read -p “Press r to repeat, any other key to continue: “ x
if [ “$x” == “r” ]; then
echo “Going again...”
continue
fi
let i=$i+1
done
$ ./continue-backwards.sh
i is 1
Press r to repeat, any other key to continue: a
i is 2
Press r to repeat, any other key to continue: r
Going again...
i is 2
Press r to repeat, any other key to continue: b
i is 3
Press r to repeat, any other key to continue: r
Going again...
i is 3
Press r to repeat, any other key to continue: c
i is 4
Press r to repeat, any other key to continue: d
$
----------------------
$ cat while-case.sh
#!/bin/bash
quit=0
while read command data
do
case $command in
echo)
echo “Found an echo command: $data”
;;
upper)
echo -en “Found an upper command: “
echo $data | tr ‘[:lower:]’ ‘[:upper:]’
;;
lower)
echo -en “Found a lower command: “
echo $data | tr ‘[:upper:]’ ‘[:lower:]’
;;
quit)
echo “Quitting as requested.”
quit=1
break
;;
*)
echo “Read $command which is not valid input.”
echo “Valid commands are echo, upper, lower, or quit.”
;;
esac
done
if [ $quit -eq 1 ]; then
echo “Broke out of the loop as directed.”
else
echo “Got to the end of the input without being told to quit.”
fi
$ ./while-case.sh
Hello
Read Hello which is not valid input.
Valid commands are echo, upper, lower, or quit.
echo Hello
Found an echo command: Hello
lower Hello
Found a lower command: hello
upper Hello
Found an upper command: HELLO
quit
Quitting as requested.
Broke out
Ctrl-D (^D) to provide an end-of-file
------------
A very useful tool for menus is called select. It originally comes from the Kornshell, but is also found
in bash.
One interesting aspect of the select loop is that it has no conditional test at all; the only way
out of the loop is to use break or exit
select continuously loops around, displaying a prompt, and
sets its variable to the value provided by the loop
What you can really do with select loops is far more open than that — you can associate absolutely
any action with each option
--------------
Probably the hardest thing when using loops in a script is determining which type of loop to use.
for loops are best at iterating over a predefined list of items; while and until loops are better at
continuing to execute code until some test condition changes. The select loop makes for really
quick and easy menuing systems.
Comments
Post a Comment