尽管此时可以通过使用 Linux 命令、管道符、重定向以及条件测试语句来编写最基本的Shell 脚本,但是这种脚本并不适用于生产环境。原因是它不能根据真实的工作需求来调整具体的执行命令,也不能根据某些条件实现自动循环执行。例如,我们需要批量创建 1000位用户,首先要判断这些用户是否已经存在;若不存在,则通过循环语句让脚本自动且依次创建他们。
4.4.1 if 条件测试语
![](https://img-blog.csdnimg.cn/20210813112319401.png)
下面使用单分支的 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
[root@localhost ~]# bash chkhost.sh baidu.com
Host baidu.com is On-line.
if 条件语句的多分支结构由 if 、 then 、 else 、 elif 、 fi 关键词组成,它进行多次条件匹配判断,这多次判断中的任何一项在匹配成功后都会执行相应的预设命令,相当于口语的“如果……那么……如果……那么……”。if 条件语句的多分支结构是工作中最常使用的一种条件判断结构,尽管相对复杂但是更加灵活,语法格式如图所示。
![](https://img-blog.csdnimg.cn/20210813141705620.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhbW8wMQ==,size_16,color_FFFFFF,t_70)
下面使用多分支的 if 条件语句来判断用户输入的分数在哪个成绩区间内,然后输出如Excellent、Pass、Fail 等提示信息。在 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 条件循环语句
![](https://img-blog.csdnimg.cn/20210816164042194.png)
![](https://img-blog.csdnimg.cn/20210817111538338.png)
接下来编写 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
[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 条件循环语句
![](https://img-blog.csdnimg.cn/20210817142923957.png)
[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 条件测试语句
![](https://img-blog.csdnimg.cn/20210817151849937.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZhbW8wMQ==,size_16,color_FFFFFF,t_70)
在前文介绍的 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