4.4 Linux流程控制语句

尽管此时可以通过使用 Linux 命令、管道符、重定向以及条件测试语句来编写最基本的Shell 脚本,但是这种脚本并不适用于生产环境。原因是它不能根据真实的工作需求来调整具体的执行命令,也不能根据某些条件实现自动循环执行。例如,我们需要批量创建 1000位用户,首先要判断这些用户是否已经存在;若不存在,则通过循环语句让脚本自动且依次创建他们。

接下来通过 if for while case 4 种流程控制语句来学习编写难度更大、功能更强的 Shell 脚本。

4.4.1 if 条件测试语

if 条件测试语句可以让脚本根据实际情况自动执行相应的命令。从技术角度来讲, if 语句分为单分支结构、双分支结构、多分支结构;其复杂度随着灵活度一起逐级上升。
if 条件语句的单分支结构由 if、then、fi 关键词组成,而且只在条件成立后才执行预设的命令,相当于口语的“如果……那么……”。 单分支的 if 语句属于最简单的一种条件判断结构,语法格式如图所示。

下面使用单分支的 if 条件语句来判断/media/cdrom 目录是否存在,若存在就结束条件判断和整个 Shell 脚本,反之则去创建这个目录:

[root@localhost ~]# vim mkcdrom.sh
[root@localhost ~]# cat mkcdrom.sh
#!/bin/bash
DIR="/mnt/zhangxu"
if [ ! -e $DIR ]
then
mkdir -p $DIR
fi
[root@localhost ~]# ls -d /mnt/zhangxu
ls: cannot access /mnt/zhangxu: No such file or directory
[root@localhost ~]# bash mkcdrom.sh
[root@localhost ~]# ls -d /mnt/zhangxu
/mnt/zhangxu

 if 条件语句的双分支结构由 if、then、else、fi 关键词组成,它进行一次条件匹配判断,如果与条件匹配,则去执行相应的预设命令;反之则去执行不匹配时的预设命令,相当于口语的“如果……那么……或者……那么……”。if 条件语句的双分支结构也是一种很简单的判断结构,语法格式如图所示。

下面使用双分支的 if 条件语句来验证某台主机是否在线,然后根据返回值的结果,要么显示主机在线信息,要么显示主机不在线信息。这里的脚本主要使用 ping 命令来测试与对方主机的网络联通性,而 Linux 系统中的 ping 命令不像 Windows 一样尝试 4 次就结束,因此为了避免用户等待时间过长,需要通过-c 参数来规定尝试的次数,并使用-i 参数定义每个数据包的发送间隔,以及使用-W 参数定义等待超时时间

[root@localhost ~]# cat chkhost.sh
#!/bin/bash
ping -c 3 -i 0.2 -W 3 $1 &> /dev/null
if [ $? -eq 0 ]
then
echo "Host $1 is On-line."
else
echo "Host $1 is Off-line."
fi
我们之前 用过 $? 变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则$? 变量会显示数字 0 ,反之则显示一个非零的数字(可能为 1 ,也可能为 2 ,取决于系统版本)。因此可以使用整数比较运算符来判断$? 变量是否为 0 ,从而获知那条语句的最终判断情况。这里的服务器 IP 地址为 baidu. com ,我们来验证一下脚本的效果:
[root@localhost ~]# bash chkhost.sh  baidu.com
Host baidu.com is On-line.

if 条件语句的多分支结构由 if then else elif fi 关键词组成,它进行多次条件匹配判断,这多次判断中的任何一项在匹配成功后都会执行相应的预设命令,相当于口语的“如果……那么……如果……那么……”。if 条件语句的多分支结构是工作中最常使用的一种条件判断结构,尽管相对复杂但是更加灵活,语法格式如图所示。

下面使用多分支的 if 条件语句来判断用户输入的分数在哪个成绩区间内,然后输出如Excellent、PassFail 等提示信息。在 Linux 系统中,read 是用来读取用户输入信息的命令,能够把接收到的用户输入信息赋值给后面的指定变量,-p 参数用于向用户显示一定的提示信息。在下面的脚本示例中,只有当用户输入的分数大于等于 85 分且小于等于 100 分,才输出Excellent 字样;若分数不满足该条件(即匹配不成功),则继续判断分数是否大于等于 70 分且小于等于 84 分,如果是,则输出 Pass 字样;若两次都落空(即两次的匹配操作都失败了),则输出 Fail 字样:

[root@localhost ~]# cat chkscore.sh
#!/bin/bash
read -p "Enter your score (0-100):" GRADE
if [ $GRADE -ge 85 ]  && [ $GRADE -le 100 ] ; then
echo "$GRADE is Excellent"
elif [ $GRADE -ge 70 ]  && [ $GRADE -le 84 ] ; then
echo "$GRADE is Pass"
else
echo "$GRADE is Fail"
fi
[root@localhost ~]# bash chkscore.sh
Enter your score (0-100):90
90 is Excellent
[root@localhost ~]# bash chkscore.sh
Enter your score (0-100):70
70 is Pass
[root@localhost ~]# bash chkscore.sh
Enter your score (0-100):10
10 is Fail
[root@localhost ~]# bash chkscore.sh
Enter your score (0-100):200
200 is Fail
为什么输入的分数为 200 时,依然显示 Fail 呢?原因很简单 没有成功匹配脚本中的两个条件判断语句,因此自动执行了最终的兜底策略。可见,这个脚本还不是很完美,建议自行完善这个脚本,使得用户在输入大于 100 或小于 0 的分数时,给予 Error 报错字样的提示。

4.4.2 for 条件循环语句

for 循环语句允许脚本一次性读取多个信息,然后逐一对信息进行操作处理,当要处理的数据有范围时,使用 for 循环语句再适合不过了。 for 循环语句的语法格式如图所示。

下面使用 for 循环语句从列表文件中读取多个用户名,然后为其逐一创建用户并设置密码。首先创建用户名称的列表文件 users.txt,每个用户名称单独一行。可以自行决定具体的用户名称和个数:

接下来编写 Shell 脚本 Example.sh。在脚本中使用 read 命令读取用户输入的密码值,然后赋值给 PASSWD 变量,并通过-p 参数向用户显示一段提示信息,告诉用户正在输入的内容即将作为账户密码。在执行该脚本后,会自动使用从列表文件 users.txt 中获取到所有的用户名称,然后逐一使用“id 用户名”命令查看用户的信息,并使用$?判断这条命令是否执行成功,也就是判断该用户是否已经存在。

[root@localhost ~]# cat Example.sh
#!/bin/bash
read -p "Enter The Users Password: " PASSWD
for UNAME in `cat users.txt`
do
id $UNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "Already exists"
else
useradd $UNAME &> /dev/null
echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "$UNAME , Create success"
else
echo "$UNAME , Create failure"
fi
fi
done
[root@localhost ~]# bash Example.sh
Enter The Users Password: 123456
zhangxu01 , Create success
zhangxu02 , Create success
zhangxu03 , Create success
zhangxu04 , Create success
zhangxu05 , Create success
zhangxu06 , Create success
zhangxu07 , Create success
zhangxu08 , Create success

 


现在已经掌握了 for 循环语句,不妨尝试让脚本从文本中自动读取主机列表,然后自动逐个测试这些主机是否在线。首先创建一个主机列表文件 ipadds.txt:
[root@localhost ~]# cat ipadds.txt
192.168.10.10
192.168.114.1
192.168.114.10
使用双分支 if 条件语句与 for 循环语句相结合,让脚本从主机列表文件 ipadds.txt 中自动读取 IP 地址(用来表示主机)并将其赋值给 HLIST 变量,从而通过判断 ping 命令执行后的返回值来逐个测试主机是否在线。脚本中出现的$ (命令)是一种完全类似于 转义字符中反引号` 命令 ` Shell 操作符,效果同样是执行括号或双引号括起来的字符串中的命令。
[root@localhost ~]# cat CheckHosts.sh
#!/bin/bash
HLIST=$( cat ~/ipadds.txt )
for IP in $HLIST
do
ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
if [ $? -eq 0 ] ; then
echo "Host $IP is On-line."
else
echo "Host $IP is Off-line."
fi
done


4.4.3 while 条件循环语句

while 条件循环语句是一种让脚本根据某些条件来重复执行命令的语句,它的循环结构往往在执行前并不确定最终执行的次数,完全不同于 for 循环语句中有目标、有范围的使用场景。while 循环语句通过判断条件测试的真假来决定是否继续执行命令,若条件为真就继续执行,为假就结束循环。while 语句的语法格式如图 所示。
接下来结合使用多分支的 if 条件测试语句与 while 条件循环语句,编写一个用来猜测数值大
小的脚本 Guess.sh 。该脚本使用 $RANDOM 变量来调取出一个随机的数值(范围为 0~ 32767 ), 将这个随机数对 1000 进行取余操作,并使用 expr 命令取得其结果,再用这个数值与用户通过 read 命令输入的数值进行比较判断。这个判断语句分为三种情况,分别是判断用户输入的数值是等于、 大于还是小于使用 expr 命令取得的数值。当前,现在这些内容不是重点,我们当前要关注的是 while 条件循环语句中的条件测试始终为 true ,因此判断语句会无限执行下去,直到用户输入的数值等于 expr 命令取得的数值后,这两者相等之后才运行 exit 0 命令,终止脚本的执行。
[root@localhost ~]# cat  Guess.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格为0-999之间,猜猜看是多少?"
while true
do
read -p "请输入您猜测的价格:" INT
let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜您答对了,实际价格是 $PRICE"
echo "您总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"
fi
done

 

4.4.4 case 条件测试语句

case 条件测试语句和 switch 语句的功能非常相似! case 语句是在多个范围内匹配数据,若匹配成功则执行相关命令并结束整个条件测试;而如果数据不在所列出的范围内,则会去执行星号(* )中所定义的默认命令 case 语句的语法结构如图所示。

 在前文介绍的 Guess.sh 脚本中有一个致命的弱点只能接受数字!您可以尝试输入一个字母,会发现脚本立即就崩溃了。原因是字母无法与数字进行大小比较,例如,“a 是否大于等于 3”这样的命题是完全错误的。我们必须有一定的措施来判断用户的输入内容,当用户输入的内容不是数字时,脚本能予以提示,从而免于崩溃。

通过在脚本中组合使用 case 条件测试语句和通配符,完全可以满足这里的需求。接下来编写脚本 2.sh,提示用户输入一个字符并将其赋值给变量 KEY,然后根据变量 KEY 的值向用户显示其值是字母、数字还是其他字符。

[root@localhost ~]# cat 2.sh
#!/bin/bash
read -p "请输入一个字符,并按Enter键确认:" KEY
case "$KEY" in
[a-z]|[A-Z])
echo "您输入的是字母"
;;
[0-9])
echo "您输入的是数字"
;;
*)
echo “您输入的是特殊字符”
esac

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值