for i in 1 2 3 4 5 6 7 8 9 10
do
echo $i
done
prints out ten lines, with a number on each line. The variable "i" is assigned the values of each of the
ten numbers. This could also be written as:
numbers="1 2 3 4 5 6 7 8 9 10"
for i in $numbers
do
echo $i
done
Change
for i in $numbers
to
for i in $numbers $numbers
and the script will output twice as many lines. The variables on the are evaluated as all variables are.
Change
for i in $numbers
to
for i in "$numbers"
and it will print out one line with all ten numbers, because there is only one argument after the "in"
command. There are many ways to specify the list of arguments in the "for" command. You can use a
Clever Thing to modify two variables in a loop, by combining the "for" command with the "set"
command:
for args in "a A" "b B" "c C"
do
set $args
echo lower case is $1, upper case is $2
done
Of course you can use back-quotes to use the output of a command as the creator of the list:
for i in `ls file*`
The line-at-a-time information is lost, as all newline characters are removed. Therefore you cannot
easily use the "set" command to modify two or more variables at a time. If you want to change multiple
arguments from a file, you either have to use the "while read" sequence I described earlier, or read a
variable, and split one variable into multiples using a command like "tr" to convert some character into
spaces, and then using "set" to change several variables at once:
#!/bin/sh
# read the /etc/password file
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
48 of 66
11/21/2011 12:03 PM
# use `cat /etc/passwd`, but spaces are treated like new lines
# therefore, change spaces into _
for i in `tr ' ' '_'
do
set `echo $i | tr ':' ' '`
echo user: $1, UID: $3, Home Directory: $6
done
You can use standard input to get the list of values for the variable:
for a in `cat`
Lastly, you can combine variables, constants, and program executions:
for i in BEGIN $a "$b $c" `cat file` END
do
echo i is $i
done
Of course any variable besides "i" will work. You don't have to specify the list of values after the "in"
command. If not specified, the positional arguments are used. To illustrate, if you had a script called
"script1" and executed
script1 a b c
and wanted to count the number of words in each file, then you could use
#!/bin/sh
echo $1 has `wc -l <$1` words
echo $2 has `wc -l <$2` words
echo $3 has `wc -l <$3` words
Another way to do the same is as follows:
#!/bin/sh
for file
do
echo $file has `wc -l <$file` words
done
Case - Checking multiple cases
The case statement functions like a complex "if" statement, with multiple clauses. The template is:
case word in pattern | pattern ) list;; esac
Let's suppose you wanted to get a yes or no answer to a question. An example is:
echo answer yes or no
read word
case $word in
yes | YES )
echo you answered yes
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
49 of 66
11/21/2011 12:03 PM
;;
no | NO )
echo you answered no
;;
esac
The "case" statement works on patterns, like filename matching. The above example won't let you
specify a single character. You must type the full word. If you type "Yes," it will not recognize it as a
yes because the first letter is upper case, and the other letters are lower case. There is a fix. The
patterns are filename patterns. Therefore you can modify the above script to be:
echo answer yes or no
read word
case $word in
[Yy]* )
echo you answered yes
;;
[Nn]* )
echo you answered no
;;
* )
echo you did not say yes or no;;
esac
You will notice the last test, containing an asterisk. This is the standard method of specifying a default
condition for the "case" statement. The last pattern in this case will always match.
There can only be one word between "case" and "in." The following is a syntax error:
case a b c in
To prevent this error, especially when the item you are checking comes from another program, use a
variable.
#!/bin/sh
arg="a b c"
case $arg in
[aAbBcC] ) echo this never matches;;
"a b c") echo this will match;;
esac
You could put quotes around "$arg," but this is not needed on my Sun system. Perhaps it is a good idea,
in case some older version of the Bourne shell has a bug. You will also notice the doubled up
semicolon. This is required. Consider this fragment:
case $arg in
a ) echo yes; b ) echo no;;
esac
The "b" looks like a command, as far as the shell knows, followed by an illegal ")." The ";;" is needed
to tell the shell the next word found is a pattern, not a command. By the way, the following is legal:
case $arg in
esac
It doesn't do anything, but the shell accepts this syntax.
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
50 of 66
11/21/2011 12:03 PM
Break and continue
The "for" and "while" commands execute each portion of code more than once. If you want to test a
condition, and exit from this loop, you can. You can control this by using the "break" or "continue"
commands. "Break" causes the control to exit the "for" or "while" statement. The "continue" statement
causes the loop to immediately start the next loop. Earlier, I used a "case" statement to check if the
input is a yes or no. If neither, an error occurs. If you want to wait until you have a proper answer, the
"break" statement can be used:
while :
do
echo "Type yes or no"
read answer
case "$answer" in
[yYnN]*) break;;
ecas
done
Notice I used the null command ":" instead of "/bin/true."" Both have the same function, but the null
command is built into the shell.
The "continue" command causes the "for" or "while" command to go to the next loop immediately The
following loop only prints the odd numbers:
for number in 1 2 3 4 5 6 7 8
do
case "$number" in
2|4|6|8) continue ;;
esac
echo $number
done
The, "for" and "while" commands can be nested. Which loops do the the "break" and "continue"
commands operate on? They work on the innermost loop, but you can override this. If you place a
number after the command, the number determines the depth of the loop. Take the following:
for number in 1 2 3 4 5 6
do
for letter in a b c d e f g
do
case $number in
3) break
esac
echo $number $letter
done
done
This will print every combination of letters and numbers, except it will not print any line with the
number "3." However, change the break to be "break 2," and the script will only print only
combinations that contain 1 or 2.
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
51 of 66
11/21/2011 12:03 PM
Dostları ilə paylaş: |