Like most programming languages, bash features a number of control structures to enable looping and conditional execution. The three most common control structures are listed in Table 4-18 ; there is also a C-style for loop that I'll discuss in the next section.
Table 4-18. Common bash control structures
Structure |
Notes |
Example |
for variable in list |
The variable is assigned the first value in list , and loop-commands are executed. The process is then repeated for all of the other values in list . |
# Set X to 'hosts', then display the filename and file contents. Repeat for 'services' |
do |
for X in hosts services |
loop-commands |
do |
done |
echo "==== $X" |
cat /etc/$X |
done |
if control-command |
If the control-command succeeds, the if-commands are executed; otherwise, the else-commands are executed. |
# Tell the user if the text 'test' appears in file1 |
then |
if grep -q test file1 |
if-commands |
then |
[else |
echo "Found it!" |
else-commands ] |
else |
fi |
echo "Not found." |
fi |
while control-command |
As long as control-command executes successfully, loop-commands are repeated. |
# Display the free disk space every 2 seconds, forever |
do |
while sleep 2 |
loop-commands |
do |
done |
df -h |
done |
The for..in control structure is great for looping over a range of values. This loop will display the status of the httpd , ftpd , and NetworkManager services:
for SERVICE in httpd ftpd NetworkManager
do
/sbin/service $SERVICE status
done
for...in is even more useful when the list of values is specified as an ambiguous filename. In this script, the loop is repeated once for each file in the directory /etc/ that ends in .conf :
mkdir backup
for FILE in /etc/*.conf
do
echo "Backing up the file $FILE..."
cp $FILE backup/
done
For the if and while control structures, a control-command determines the action taken. The control-command can be any command on the system; an exit status of zero is considered TRue and any other exit status is considered false .
For example, the grep command exits with a value of zero if a given pattern is found in the file(s) specified or in the standard input. When combined with an if structure, you can cause a program to take a particular action if a pattern is found. For example, this code displays the message "Helen is logged in!" if the output of who contains the word helen :
if who | grep -q helen
then
echo "Helen is logged in!"
fi
The exit status of the last command is taken as the exit status of a pipeline, which is grep in this case. The -q argument to grep suppresses the outputotherwise, matching lines are sent to standard output.
The built-in command test can be used to test conditions; the exit status will be zero if the condition is TRue . The most common conditional expressions are listed in Table 4-19.
Table 4-19. Common bash conditional operators
Operator |
Tests whether... |
Example using an environment variable |
-f file |
File exists and is a regular file |
-f "$A" |
-d file |
File exists and is a directory |
-d "$B" |
-r file |
File exists and is readable |
-r "$C" |
-w file |
File exists and is writable |
-w "$D" |
-x file |
File exists and is executable |
-x "$E" |
value1 == value2 |
Strings match |
"$F" == "red" |
value1 != value2 |
Strings don't match |
"$G" != "blue" |
value1 -eq value2 |
Integer values are equal |
"$H" -eq 2 |
value1 -ne value2 |
Integer values are unequal |
"$J" -ne 10 |
value1 -gt value2 |
value1 integer value is greater than value2 |
"$K" -gt 25 |
value1 -ge value2 |
value1 integer value is greater than or equal to value2 |
"$L" -ge 25 |
value1 -lt value2 |
value1 integer value is less than value2 |
"$M" -lt 75 |
value1 -le value2 |
value1 integer value is less than or equal to value2 |
"$N" -le 75 |
expression1 -a expression2 |
expression1 and expression2 are both true |
"$P" -gt 36 -a "$P" -lt 71 |
expression1 -o expression2 |
expression1 or expression2 (or both) are true |
"$P" -lt 12 -o "$P" -eq 50 |
So if you wanted to print "Too high!" if the value of the variable A was over 50, you would write:
if test "$A" -gt 50
then
echo "Too high!"
fi
The variable expression $A is quoted in case A has a null value ("") or doesn't existin which case, if unquoted, a syntax error would occur because there would be nothing to the left of -gt .
The square brackets ( [] ) are a synonym for test , so the previous code is more commonly written:
if [ "$A" -gt 50 ]
then
echo "Too high!"
fi
You can also use test with the while control structure. This loop monitors the number of users logged in, checking every 15 seconds until the number of users is equal to or greater than 100, when the loop will exit and the following pipeline will send an email to the email alias alert :
while [ "$(who | wc -l)" -lt 100 ]
do
sleep 15
done
echo "Over 100 users are now logged in!"|mail -s "Overload!" alert
4.12.1.4. Integer arithmetic
bash provides very limited integer arithmetic capabilities. An expression inside double parentheses (( )) is interpreted as a numeric expression; an expression inside double parentheses preceded by a dollar sign $(( )) is interpreted as a numeric expression that also returns a value.
Inside double parentheses, you can read a variable's value without using the dollar sign (use A=B+C instead of A=$B+$C).
Here's an example using a while loop that counts from 1 to 20 using integer arithmetic:
A=0
while [ "$A" -lt 20 ]
do
(( A=A+1 ))
echo $A
done
The C-style increment operators are available, so this code could be rewritten as:
A=0
while [ "$A" -lt 20 ]
do
Читать дальше