分类:
2010-10-19 18:21:23
10.3流程控制结构
v 控制结构一般有三种:
顺序结构;
分支结构;
循环结构。
10.3.1 顺序结构
v 顺序结构是程序中最简单的控制结构,从脚本的开始到结束,按照顺序执行每一条语句。
v 请看以下示例:
v 顺序结构示例:读用户输入的姓名并显示。
[root@server root]#cat e7.sh
#!/bin/sh
echo "Hello !"
echo -n "What's your name: "
read yourname
echo "Hello $yourname !"
exit 0
[root@server root]# ./e7.sh
Hello !
What's your name: Tom
Hello Tom !
v 查看本示例的退出状态如下:
[root@server root]#echo $?
0
10.3.2 条件测试
v shell中提供了test命令来实现上述的条件测试功能。
v 在shell脚本中条件测试既可以用在分支结构中,又可以用在循环结构中。
1.test命令
(1)test命令有两种使用格式:
第一种是在test语句后加上测试条件;
第二种是用方括号代替test。
(2)test命令的格式如下:
test 测试条件
或
[ 测试条件 ]
2.文件测试
v 文件测试条件示例:
[root@server myshell]# test –f e2.sh
[root@server myshell]# echo $?
0
功能:测试文件e2.sh是否为普通文件,测试结果为e2.sh是普通文件。
[root@server myshell]# [ -f e60.sh ]
[root@server myshell]# echo $?
1
要求:测试文件le2.sh是否为符号连接文件
[root@server myshell]# ln -s e2.sh le2.sh
[root@server myshell]# [ -L le2.sh ]
[root@server myshell]# echo $?
0
v 要求:测试文件/dev/hda1是否是块设备文件。
[root@server myshell]# [ -b /dev/hda1 ]
[root@server myshell]# echo $?
0
更多文件测试请参见P61
3.字符串测试
3.字符串测试
v 字符串测试示例:
[root@server root]#echo $LOGNAME
root
[root@server root]#[ $LOGNAME = “root” ]
[root@server root]#echo $?
0
4.数值测试
v expr1 –eq expr2
功能:当表达式expr1的值与表达式expr2的值相等
v expr1 –ne expr2
功能:当表达式expr1的值与表达式expr2的值不相等
v expr1 –gt expr2
功能:当表达式expr1的值大于与表达式expr2的值
v expr1 –lt expr2
功能:当表达式expr1的值小于与表达式expr2的值
v expr1 –ge expr2
功能:当表达式expr1的值大于等于表达式expr2的值
v expr1 –le expr2
功能:当表达式expr1的值小于等于表达式expr2的值
数值测试示例:
[root@ server root]# a=10
[root@ server root]# b=20
[root@ server root]# declare -i c
[root@ server root]# c=$a+$b
[root@ server root]# echo $c
30
[root@ server root]# [ $c -eq 30 ]
[root@ server root]# echo $?
0
[root@ server root]# [ $c -eq "30" ]
[root@ server root]# echo $?
0
[root@ server root]# [ $c -ne 30 ]
[root@ server root]# echo $?
1
[root@ server root]# [ $c -ge 35 ]
[root@ server root]# echo $?
1
5.逻辑操作符
v shell提供的逻辑操作符有三个:
一是逻辑与、
二是逻辑或、
三是逻辑非。
v 逻辑与操作符示例:
[root@ server root]# name=Tom
[root@ server root]# password=abc
[root@ server root]# [ $name = “Tom” –a $password = “abc” ]
[root@ server root]# echo $?
0
功能:测试变量$name是否等于“Tom”并且$password是否等于“abc”。
示例:
[root@ server root]# ls –l e3.sh
-rw-r--r-- 1 root root 41 Jan 14 12:16 e3.sh
[root@ server root]# [ -r e3.sh -a -x e3.sh ]
[root@ server root]#l echo $?
1
功能:测试文件e3.sh是否同时具有读权限和可执行权限。
逻辑或操作符示例:
[root@ server root]# name=Tom
[root@ server root]# password=abc
[root@ server root]# [ $name = “Tom” -o $password = “123456”]
[root@ server root]# echo $?
0
v 逻辑非操作符示例:
[root@ server root]# ls –l e3.sh
-rw-r--r-- 1 root root 41 Jan 14 12:16 e3.sh
[root@ server root]# [ -x e3.sh ]
[root@ server root]# echo $?
1
[root@ server root]# [ ! –x e3.sh ]
[root@ server root]# echo $?
0
需要注意的是,逻辑非“!”的两边也必须各有一个空格。
10.3.3 分支结构
v 在shell中有两种形式的分支结构:
一种是if分支结构,
另一种case分支结构。
1.if分支结构
v if分支结构的基本格式如下:
if 条件测试1; then
条件测试1为真时的语句序列
[elif条件测试2; then]
条件测试2为真时的语句序列
...
[else]
条件测试为假时的语句序列
fi
v if分支结构示例一:用户输入字符串,判断其内容是否与存储在变量$name中的内容相同。
[root@server root]# cat e10.sh
#!/bin/sh
name="garfield"
echo -n "Please input:"
read uservalue
if [ $uservalue = $name ]; then
echo "same"
else
echo "difference"
fi
执行:
[root@server root]# ./e10.sh
Please input:abc
difference
[root@server root]# ./e10.sh
Please input:garfield
same
v if分支结构示例二:判断今天是不是星期一。
[root@server root]# cat e12.sh
#!/bin/sh
today=`date +%u`
if [ $today = 1 ]; then
echo "Today is Monday"
else
echo " Today is not Monday "
fi
v 执行:
[root@server root]# date
Sun Jan 14 17:12:25 CST 2007
[root@server root]# ./e12.sh
Today is not Monday
v if分支结构示例三:判断用户指定文件的类型。
[root@server root]# cat e13.sh
#!/bin/sh
usefile=$1
if [ -d $usefile ]; then
echo "directory"
elif [ -f $usefile ]; then
echo "normal"
elif [ -b $usefile ]; then
echo "block device"
elif [ -c $usefile ]; then
echo "char device"
else
echo "other"
fi
执行:
[root@server root]# ./e13.sh e13.sh
normal
2.case分支结构
case语句的结构如下:
case 值 in
模式1)
语句组1
… …
;;
模式2)
语句组2
……
;;
……
*)
语句组n
esac
case分支结构示例一:通过判断$1的值,设置用户指定文件的权限。
[root@server root]# cat e16.sh
#!/bin/sh
option=$1
filename=$2
case $option in
r)
chmod u+r $filename
;;
w)
chmod u+w $filename
;;
x)
chmod u+x $filename
;;
*)
echo "error!"
exit 1
;;
esac
exit 0
[root@server root]# ls -l abc
-rw-r--r-- 1 root root 161 Jan 13 21:36 abc
[root@server root]# ./e16.sh x abc
[root@server root]# ls -l abc
-rwxr--r-- 1 root root 161 Jan 13 21:36 abc
v case分支结构示例二:提示键入“y”或“n”,根据实际输入执行相应分支。
#!/bin/sh
echo -n "Please input your choice [y|n]:"
read ch
case $ch in
y|Y|yes||YES)
echo " go on "
;;
n|N|no|NO)
echo "cancel"
;;
*)
echo "error ,you should input[y|n]"
exit 1
;;
esac
exit 0
v 执行:
[root@server root]# ./e17.sh
Please input your choice [y|n]:y
go on
10.3.4 循环结构
1.for循环
其典型格式如下:
for 变量 in 值1值2 …值n
do
语句1
语句2
……
done
for循环示例一:显示全部位置变量参数。
[root@server root]# cat e19.sh
#!/bin/sh
for i in $@
do
echo $i
done
[root@server root]#./e19.sh a b c "d e"
a
b
c
d e
说明:如果省略了in,则默认从$*或$@中取值。
for循环示例二:显示$PATH变量中各目录的名称。
[root@server root]# cat e20.sh
#!/bin/sh
IFS=:
for dir in $PATH
do
ls -ld $dir
done
echo "Finished!"
v 执行:
[root@server root]#./e20.sh
drwxr-xr-x 2 root root 4096 Feb 7 1996 /usr/local/bin
drwxr-xr-x 2 root root 4096 Feb 18 2003 /bin
drwxr-xr-x 2 root root 36864 Aug 24 22:00 /usr/bin
drwxr-xr-x 2 root root 4096 Feb 18 2003 /usr/X11R6/bin
Finished!
for循环示例三:与C语言相似的格式用法。
[root@server root]#cat ./e21.sh
#!/bin/sh
for ((i=1;i<=6;i++))
do
for((j=1;j<=i;j++))
do
echo -e "*\c"
done
echo
done
[root@server root]# ./e21.sh
*
**
***
****
*****
******
2.while循环
while循环的格式如下:
while 条件
do
语句1
语句2
……
done
v while循环示例:逐行显示一个文本文件的内容,忽略以符号“#”开头的行,并在所显示的每一行前加上行号。
[root@server root]# cat e23.sh
#!/bin/sh
counter=1
while read line
do
if ! [ ${line:0:1} = "#" ]; then
echo "$counter: $line"
counter=$[counter+1]
fi
done < $1
[root@server root]# ./e23.sh e23.sh
1: counter=1
2: while read line
3: do
4: if ! [ ${line:0:1} = "#" ]; then
5: echo "$counter: $line"
6: counter=$[counter+1]
7: fi
8: done < $1
3.select循环
格式如下:
select name [ in list ]
do
语句列表
done
select提供了一个菜单循环选项,供用户选择,并有以下特点:
1)其中list中的每一项都对应一个数字,用户键入的值会被存到变量REPLY。
2)select用到了PS3提示符 ,默认值为#?,用户可以更改。
3)select是无限循环,所以应在循环体内提供退出循环的语句。
[root@server root]# cat e24.sh
#!/bin/sh
select myoption in shopping fishing cooking quitting
do
case $myoption in
shop*) echo I want to go $myoption with lots of money.
;;
fish*) echo I want to go $myoption with John.
;;
cooking) echo I am cooking a small fish.
;;
quit*) echo bye.
break
;;
*) echo try again!
;;
esac
done
echo "Finished!"
v 执行:
[root@server root]#./e24.sh
1) shopping
2) fishing
3) cooking
4) quitting
#? 2
I want to go fishing with John.
#? 3
I am cooking a small fish.
#? 4
bye.
Finished!
3.4 shell函数
3.4.1 函数的定义
在shell中定义函数有两种格式:
function funcname
{
shell commands
}
或
funcname()
{
shell commands
}
定义函数示例:定义一个shell函数。
[root@server root]# cat e29.sh
#!/bin/sh
myfunction()
{
echo "Hello,world!"
}
10.4.2 函数的调用与执行
v 调用shell函数示例:利用select循环、case语句调用定义好的函数。
[root@server myshell]# cat e25.sh
#!/bin/sh
ps_fun()
{
ps aux
}
function log_fun
{
tail /var/log/messages
}
ls_fun()
{
ls -la
}
select myaction in display_proc show_log list_dir quit
do
case $myaction in
display_proc)
ps_fun ;;
show_log)
log_fun ;;
list_dir)
ls_fun ;;
quit)
break ;;
*)
echo error ;;
esac
done
v 执行:
[root@server myshell]# ./e25.sh
1) display_proc
2) show_log
3) list_dir
4) quit
#? 3
total 40
drwxr-xr-x 2 root root 4096 Jan 14 19:38 .
drwxr-x--- 24 root root 4096 Jan 14 19:38 ..
-rwxr-xr-x 1 root root 36 Jan 14 18:02 e19.sh
-rwxr-xr-x 1 root root 101 Jan 14 18:19 e21.sh
10.4.3 参数的传递
v 函数的参数与脚本的参数非常相似,也是使用$1、$2……,以及$#等特殊变量。
v 请看如下示例。
v 参数的传递示例:由用户控制循环的次数。
[root@server myshell]# cat ./e26.sh
#!/bin/sh
my_fun()
{
over=$1
counter=1
while [ $counter -le $over ]
do
echo $counter
counter=$[counter+1]
done
}
echo -n "Please input a number:"
read num
my_fun $num
v 执行:
[root@server myshell]# ./e26.sh
Please input a number:5
1
2
3
4
5
10.4.4 函数的返回
在函数中使用return语句,可以完成这个功能,其语法如下:
return
从函数中返回, 上一条语句的执行状态决定返回值。
return 0
返回值为0,一般表示无错误返回。
return 1
返回值为1,一般表示有错误返回。
10.5本章小结
v bash脚本编程的基本概念
v 语句、流程控制
v 环境变量、引用、变量替换、条件测试、分支、循环结构
#! /bin/sh
is_directory()
{
DIR_NAME=$1
if [ ! -d $DIR_NAME ]; then
return 0
else
return 1
fi
}
for DIR in "$@"
do
if is_directory "$DIR"
then
echo "$DIR doesn't exist. Creating it now..."
mkdir $DIR
if [ $? -ne 0 ]; then
echo "Cannot create directory $DIR"
exit 1
fi
fi
done
注意is_directory()返回0表示真返回1表示假。