24: 条件测试 、 if选择结构 、 循环结构 、 总结和答疑

Top

NSD SHELL DAY02

  1. 案例1:条件测试操作
  2. 案例2:使用if选择结构
  3. 案例3:使用for循环结构
  4. 案例4:使用while循环结构

1 案例1:条件测试操作

1.1 问题

本案例要求参考PPT上的示例,分别练习以下条件测试操作:

  • 字符串匹配
  • 比较整数值的大小
  • 识别文件/目录的状态
  • 多个条件/操作的逻辑组合

1.2 步骤

实现此案例需要按照如下步骤进行。

步骤一:条件测试的基本用法

1)语法格式

使用“test 表达式”或者[ 表达式 ]都可以,表达式两边至少要留一个空格。

条件测试操作本身不显示出任何信息。测试的条件是否成立主要体现在命令执行后的返回状态(即 $?),所以可以在测试后查看变量$?的值来做出判断,或者结合&&、||等逻辑操作显示出结果(或作其他操作) 。

步骤二:字符串测试

1)== 比较两个字符串是否相同

检查当前用户是否为root。

当root用户执行时:

[root@svr5 ~]# [ $USER == "root" ] 		//测试
[root@svr5 ~]# echo $?					//查看结果0为对,非0为错

当普通用户执行时:

[zengye@svr5 ~]$ [ $USER == "root" ]
[zengye@svr5 ~]$ echo $?                    //查看结果0为对,非0为错

2)!= 比较两个字符串是否不相同

当普通用户执行时:

[zengye@svr5 ~]$ [ $USER != "root" ] 

当root用户执行时:

[root@svr5 ~]# [ $USER != "root" ]

3)一行执行多条命令的情况

# A && B    					//仅当A命令执行成功,才执行B命令
# A || B						//仅当A命令执行失败,才执行B命令
# A ;  B						//执行A命令后执行B命令,两者没有逻辑关系
# A && B || C                   //思考?

4) -z 检查变量的值是否未设置(空值)

[root@svr5 ~]# var1="nb" ; var2=""
[root@svr5 ~]# [ -z "$var1" ] && echo "空值" || echo "非空值"
非空值
[root@svr5 ~]# [ -z $var2 ] && echo "空值" || echo "非空值"
空值  									//变量var2已设置,但无任何值,视为空
[root@svr5 ~]# [ ! -z $var1 ]				//测试var1是否为非空

还有一个-n可以测试变量是否不为空(相当于! -z)。

步骤三:整数值比较

参与比较的必须是整数(可以调用变量),比较非整数值时会出错:

[root@svr5 ~]# A=20.4
[root@svr5 ~]# [ $A -gt 10 ]  				//不支持小数比较
-bash: [: 20.4: integer expression expected

1)-eq 比较两个数是否相等。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -eq 20 ] && echo "相等" || echo "不相等"
相等
[root@svr5 ~]# [ $X -eq 30 ] && echo "相等" || echo "不相等"
不相等

2)-ne 比较两个数是否不相等。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -ne 20 ] && echo "不等于" || echo "等于"
等于
[root@svr5 ~]# [ $X -ne 30 ] && echo "不等于" || echo "等于"
不等于

3)-gt 比较前面的整数是否大于后面的整数。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -gt 10 ] && echo "大于" || echo "否"
大于
[root@svr5 ~]# [ $X -gt 20 ] && echo "大于" || echo "否"
否
[root@svr5 ~]# [ $X -gt 30 ] && echo "大于" || echo "否"
否

4)-ge 比较前面的整数是否大于或等于后面的整数。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -ge 10 ] && echo "大于或等于" || echo "否"
大于或等于
[root@svr5 ~]# [ $X -ge 20 ] && echo "大于或等于" || echo "否"
大于或等于
[root@svr5 ~]# [ $X -ge 30 ] && echo "大于或等于" || echo "否"
否

5)-lt 比较前面的整数是否小于后面的整数。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -lt 10 ] && echo "小于" || echo "否"
否
[root@svr5 ~]# [ $X -lt 20 ] && echo "小于" || echo "否"
否
[root@svr5 ~]# [ $X -lt 30 ] && echo "小于" || echo "否"
小于

6)-le 比较前面的整数是否小于或等于后面的整数。

[root@svr5 ~]# X=20  						//定义一个测试变量
[root@svr5 ~]# [ $X -le 10 ] && echo "小于或等于" || echo "否"
否
[root@svr5 ~]# [ $X -le 20 ] && echo "小于或等于" || echo "否"
小于或等于
[root@svr5 ~]# [ $X -le 30 ] && echo "小于或等于" || echo "否"
小于或等于

7)提取当前登录的用户数,比较是否大于等于3。

[root@svr5 ~]# who | wc -l  								//确认已登录的用户数
2
[root@svr5 ~]# N=$(who | wc -l)  							//赋值给变量N
[root@svr5 ~]# [ $N -ge 3 ] && echo "超过了" || echo "没超过"
没超过

上述赋值给变量N及与3比较的操作,可以简化为如下形式:

[root@svr5 ~]# [ $(who | wc -l) -ge 3 ] && echo "超过了" || echo "没超过"
没超过

步骤四:识别文件/目录的状态

1)-e 判断对象是否存在(不管是目录还是文件)

[root@svr5 ~]# [ -e "/usr/" ] && echo "存在" || echo "不存在"
存在
[root@svr5 ~]# [ -e "/etc/fstab" ] && echo "存在" || echo "不存在"
存在
[root@svr5 ~]# [ -e "/home/nooby" ] && echo "存在" || echo "不存在"
不存在

2)-d 判断对象是否为目录(存在且是目录)

[root@svr5 ~]# [ -d "/usr/" ] && echo "是目录" || echo "不是目录"
是目录
[root@svr5 ~]# [ -d "/etc/fstab" ] && echo "是目录" || echo "不是目录"
不是目录
[root@svr5 ~]# [ -d "/home/nooby" ] && echo "是目录" || echo "不是目录"
不是目录

3)-f 判断对象是否为文件(存在且是文件)

[root@svr5 ~]# [ -f "/usr/" ] && echo "是文件" || echo "不是文件"
不是文件
[root@svr5 ~]# [ -f "/etc/fstab" ] && echo "是文件" || echo "不是文件"
是文件
[root@svr5 ~]# [ -f "/home/nooby" ] && echo "是文件" || echo "不是文件"
不是文件

4)-r 判断对象是否可读

此测试对root用户无效,无论文件是否设置r权限,root都可读:

[root@svr5 ~]# cp /etc/hosts /tmp/test.txt  		//复制一个文件做测试
[root@svr5 ~]# chmod -r /tmp/test.txt  			//去掉所有的r权限
[root@svr5 ~]# [ -r "/tmp/test.txt" ] && echo "可读" || echo "不可读"
可读  											//root测试结果仍然可读

切换为普通用户,再执行相同的测试,结果变为“不可读”:

[zengye@svr5 ~]$ [ -r "/tmp/test.txt" ] && echo "可读" || echo "不可读"
不可读

5)-w 判断对象是否可写

此测试同样对root用户无效,无论文件是否设置w权限,root都可写:

[root@svr5 ~]# chmod -w /tmp/test.txt 			//去掉所有的w权限
[root@svr5 ~]# ls -l /tmp/test.txt  			//确认设置结果
---------- 1 root root 33139 12-11 10:43 /tmp/test.txt
[root@svr5 ~]# [ -w "/tmp/test.txt" ] && echo "可写" || echo "不可写"
可写

切换为普通用户,可以正常使用-w测试:

[zengye@svr5 ~]$ ls -l /tmp/test.txt
---------- 1 root root 33139 12-11 10:52 /tmp/test.txt
[zengye@svr5 ~]$ [ -w "/tmp/test.txt" ] && echo "可写" || echo "不可写"
不可写

6)-x 判断对象是否具有可执行权限

这个取决于文件本身、文件系统级的控制,root或普通用户都适用:

[root@svr5 ~]# chmod 644 /tmp/test.txt  		//重设权限,无x
[root@svr5 ~]# ls -l /tmp/test.txt  			//确认设置结果
-rw-r--r-- 1 root root 33139 12-11 10:52 /tmp/test.txt
[root@svr5 ~]# [ -x "/tmp/test.txt" ] && echo "可执行" || echo "不可执行"
不可执行
[root@svr5 ~]# chmod +x /tmp/test.txt  		//添加x权限
[root@svr5 ~]# [ -x "/tmp/test.txt" ] && echo "可执行" || echo "不可执行"
可执行

步骤五:多个条件/操作的逻辑组合

1)&&,逻辑与

给定条件必须都成立,整个测试结果才为真。

检查变量X的值是否大于10,且小于30:

[root@svr5 ~]# X=20  					//设置X变量的值为20
[root@svr5 ~]# [ $X -gt 10 ] && [ $X -lt 30 ] && echo "YES"
YES

2)||,逻辑或

只要其中一个条件成立,则整个测试结果为真。

只要/tmp/、/var/spool/目录中有一个可写,则条件成立:

[root@svr5 ~]# [ -w "/tmp/" ] || [ -w "/var/spool/" ] && echo "OK"
OK

2 案例2:使用if选择结构

2.1 问题

本案例要求编写3个Shell脚本,分别实现以下目标:

  • 检测/media/cdrom目录,若不存在则创建
  • 检测并判断指定的主机是否可ping通
  • 从键盘读取一个论坛积分,判断论坛用户等级,等级分类如下:

大于等于90 神功绝世

大于等于80,小于90 登峰造极

大于等于70,小于80 炉火纯青

大于等于60,小于70 略有小成

小于60 初学乍练

2.2 方案

if单分支的语法组成:

if  条件测试
then  
命令序列
fi

if双分支的语法组成:

if  条件测试
then
命令序列1
else  
命令序列2
fi

if多分支的语法组成:

if    条件测试1 ;then  
命令序列1
elif  条件测试2 ;then  
命令序列2
else
命令序列n
fi

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:检测/media/cdrom目录,若不存在则创建

1)编写脚本如下:

[root@svr5 ~]# vim mountdir.sh 
#!/bin/bash
dir="/media/cdrom/"
if [ ! -d $dir ]
then
    mkdir -p $dir
fi 

[root@svr5 ~]# chmod +x mountdir.sh //添加可执行权限

2)测试、验证脚本功能


[root@svr5 ~]# ls -ld /media/cdrom  				//本来没有/media/cdrom目录
ls: /media/cdrom: 没有那个文件或目录
[root@svr5 ~]# ./mountdir.sh //执行脚本
[root@svr5 ~]# ls -ld /media/cdrom //再检查已经有了
drwxr-xr-x 2 root root 4096 12-11 15:16 /media/cdrom

有了/media/cdrom文件夹以后,再次执行上述脚本,实际上不做任何有效操作:


[root@svr5 ~]# ./mountdir.sh

步骤二:检测并判断指定的主机是否可ping通


1)分析任务需求


使用ping命令检测目标主机时,人工可直接判断反馈结果,而脚本却不方便。但是当ping测试成功时,执行状态 ? 的 值 为 0 ; 而 p i n g 测 试 失 败 时 , ?的值为0;而ping测试失败时, ?0ping?的值不为0。因此在Shell脚本中可以利用这一点来判断ping目标主机的成败。


为了节省ping测试时间,可以只发送3个测试包(-c 3)、缩短发送测试包的间隔秒数(-i 0.2)、等待反馈的超时秒数(-W 1)。比如,检查可ping通的主机:


[root@svr5 ~]# ping -c 3 -i 0.2 -W 1 192.168.4.5
PING 192.168.4.5 (192.168.4.5) 56(84) bytes of data.
64 bytes from 192.168.4.5: icmp_seq=1 ttl=64 time=0.131 ms
64 bytes from 192.168.4.5: icmp_seq=2 ttl=64 time=0.076 ms
64 bytes from 192.168.4.5: icmp_seq=3 ttl=64 time=0.073 ms

— 192.168.4.5 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 402ms
rtt min/avg/max/mdev = 0.073/0.093/0.131/0.027 ms

[root@svr5 ~]# echo $? //执行状态表示成功
0

2)脚本编写参考如下:


[root@svr5 ~]# vim pinghost.sh
#!/bin/bash
ping -c 3 -i 0.2 -W 1 $1 &> /dev/null
if [ $? -eq 0 ] ; then
echo “Host $1 is up.”
else
echo “Host $1 is down.”
fi

[root@svr5 ~]# chmod +x pinghost.sh

3)测试、验证脚本功能


[root@svr5 ~]# ./pinghost.sh 192.168.4.5
Host 192.168.4.5 is up.
[root@svr5 ~]# ./pinghost.sh 192.168.4.50
Host 192.168.4.50 is down.

步骤三:从键盘读取一个论坛积分,判断论坛用户等级


1)脚本编写参考如下:


大于等于90 神功绝世


大于等于80,小于90 登峰造极


大于等于70,小于80 炉火纯青


大于等于60,小于70 略有小成


小于60 初学乍练


[root@svr5 ~]# vim grade.sh
#!/bin/bash
read -p “请输入积分(0-100):” JF
if [ J F − g e 90 ] ; t h e n e c h o " JF -ge 90 ] ; then echo " JFge90];thenecho"JF 分,神功绝世"
elif [ J F − g e 80 ] ; t h e n e c h o " JF -ge 80 ] ; then echo " JFge80];thenecho"JF 分,登峰造极"
elif [ J F − g e 70 ] ; t h e n e c h o " JF -ge 70 ] ; then echo " JFge70];thenecho"JF 分,炉火纯青"
elif [ J F − g e 60 ] ; t h e n e c h o " JF -ge 60 ] ; then echo " JFge60];thenecho"JF 分,略有小成"
else
echo “$JF 分,初学乍练”
fi

[root@svr5 ~]# chmod +x grade.sh

3)测试、验证脚本


[root@svr5 ~]# ./grade.sh
请输入积分(0-100):74
74 分,炉火纯青
[root@svr5 ~]# ./grade.sh
请输入分数(0-100):68
68 分,略有小成
[root@svr5 ~]# ./grade.sh
请输入分数(0-100):87
87 分,登峰造极

3 案例3:使用for循环结构

3.1 问题

本案例要求编写一个Shell脚本chkhosts.sh,利用for循环来检测多个主机的存活状态,相关要求及说明如下:

  • 对192.168.4.0/24网段执行ping检测
  • 脚本能遍历ping各主机,并反馈存活状态

执行检测脚本以后,反馈结果如图-1所示。

图-1

3.2 方案

在Shell脚本应用中,常见的for循环采用遍历式、列表式的执行流程,通过指定变量从值列表中循环赋值,每次复制后执行固定的一组操作。

for循环的语法结构如下所示:

for  变量名  in  值列表
do
    命令序列
done

for 变量名 in {1…5}
do
命令序列
done
for 变量名 in seq 5
do
命令序列
done

for 变量名 in ls /etc/*.conf
do
命令序列
done

3.3 步骤


实现此案例需要按照如下步骤进行。


步骤一:练习for循环基本用法


脚本1,通过循环批量显示5个hello world:


[root@svr5 ~]# vim for01.sh
#!/bin/bash
for i in 1 2 3 4 5
do
echo “hello world”
done
[root@svr5 ~]# chmod +x for01.sh
[root@svr5 ~]# ./for01.sh

脚本2,通过循环批量显示10个hello world:


[root@svr5 ~]# vim for02.sh
#!/bin/bash
for i in {1…10}
do
echo “hello world”
done
[root@svr5 ~]# chmod +x for02.sh
[root@svr5 ~]# ./for02.sh

脚本3,通过循环批量显示10个数字:


[root@svr5 ~]# vim for03.sh
#!/bin/bash
for i in {1…10}
do
echo “KaTeX parse error: Expected 'EOF', got '#' at position 22: …e [root@svr5 ~]#̲ chmod +x for03…i &> /dev/null
if [ ? − e q 0 ] ; t h e n e c h o " H o s t 192.168.4. ? -eq 0 ] ; then echo "Host 192.168.4. ?eq0];thenecho"Host192.168.4.i is up.”
else
echo “Host 192.168.4.$i is down.”
fi
done
[root@svr5 ~]# chmod +x chkhosts.sh

4)测试、验证脚本


… …
[root@svr5 ~]# ./chkhosts.sh
Host 192.168.4.5 is up.
Host 192.168.4.6 is down
… …

步骤三:创建账户的案例


创建users.txt,写入无规律的账户名称,最后使用for循环读取该文件,批量创建账户并设置密码。


[root@svr5 ~]# vim addfor.sh
#!/bin/bash
for i in cat /root/user.txt
do
useradd $i
echo 123456 | passwd --stdin $i
done

附加扩展知识(C语言风格的for循环语法格式)


[root@svr5 ~]# vim cfor.sh
#!/bin/bash
for ((i=1;i<=5;i++))
do
echo $i
done



4 案例4:使用while循环结构


4.1 问题


本案例要求编写2个使用while循环的脚本程序,分别实现以下目标:



  • 提示用户猜测一个随机数,直到才对为止
  • 检测192.168.4.0/24网段,列出不在线的主机地址
  • 4.2 方案

    while循环属于条件式的执行流程,会反复判断指定的测试条件,只要条件成立即执行固定的一组操作,直到条件变化为不成立为止。所以while循环的条件一般通过变量来进行控制,在循环体内对变量值做相应改变,以便在适当的时候退出,避免陷入死循环。

    while循环的语法结构如下所示:

    while  条件测试
    do
        命令序列
    done
    

    while :
    do
    命令序列
    done

    4.3 步骤


    实现此案例需要按照如下步骤进行。


    步骤一:练习while循环基本用法


    脚本1,无心的死循环脚本:


    [root@svr5 ~]# vim while01.sh
    #!/bin/bash
    i=1
    while [ i − l e 5 ] d o e c h o " i -le 5 ] do echo " ile5]doecho"i"
    done
    [root@svr5 ~]# chmod +x while01.sh
    [root@svr5 ~]# ./while01.sh //死循环,需要使用Ctrl+C终止脚本

    脚本2,有效循环脚本:


    [root@svr5 ~]# vim while02.sh
    #!/bin/bash
    i=1
    while [ i − l e 5 ] d o e c h o " i -le 5 ] do echo " ile5]doecho"i"
    let i++
    done
    [root@svr5 ~]# chmod +x while02.sh
    [root@svr5 ~]# ./while02.sh

    脚本3,死循环的一般格式:


    [root@svr5 ~]# vim while03.sh
    #!/bin/bash
    while :
    do
    echo “hello world”
    done
    [root@svr5 ~]# chmod +x while03.sh
    [root@svr5 ~]# ./while03.sh //死循环,需要使用Ctrl+C终止脚本

    步骤二:提示用户猜测一个随机数,直到才对为止


    使用系统自带变量RANDOM提取随机数(1-100),使用while :制作死循环。


    脚本编写参考如下:


    [root@svr5 ~]# vim guess.sh
    #!/bin/bash
    num=$[RANDOM%100+1]
    i=0
    while :
    do
    read -p “随机数1-100,你猜:” guess
    let i++ //猜一次,计数器加1,统计猜的次数
    if [ $guess -eq n u m ] ; t h e n e c h o " 恭 喜 , 猜 对 了 " e c h o " 你 猜 了 num ];then echo "恭喜,猜对了" echo "你猜了 num];thenecho""echo"i次"
    exit
    elif [ $guess -gt $num ];then
    echo “猜大了”
    else
    echo “猜小了”
    fi
    [root@svr5 ~]# chmod +x guess.sh

    执行脚本并验证结果:


    [root@svr5 ~]# ./guess.sh

    步骤三:检测192.168.4.0/24网段,列出不在线的主机地址


    1)任务需求及思路分析


    要求的是“检测192.168.4.0/24网段,列出不在线的主机地址”。


    检测目标是一个网段,其网络部分“192.168.4.”可以作为固定的前缀;而主机部分包括从1~254连续的地址,所以可结合while循环和自增变量进行控制。


    2)根据实现思路编写脚本


    [root@svr5 ~]# vim chknet.sh
    #!/bin/bash
    i=1
    while [ i − l e 254 ] d o I P = " 192.168.4. i -le 254 ] do IP="192.168.4. ile254]doIP="192.168.4.i"
    ping -c 3 -i 0.2 -W 1 $IP &> /dev/null
    if [ $? -eq 0 ] ; then
    echo “Host $IP is up.”
    else
    echo “Host $IP is down.”
    fi
    let i++
    done
    [root@svr5 ~]# chmod +x chknet.sh

    3)测试、验证脚本


    [root@svr5 ~]# ./chknet.sh
    Host 192.168.4.1 is down.
    Host 192.168.4.2 is down.
    Host 192.168.4.3 is down.
    Host 192.168.4.4 is down.
    Host 192.168.4.5 is up.
    … …
    Host 192.168.4.250 is down.
    Host 192.168.4.251 is down.
    Host 192.168.4.252 is down.
    Host 192.168.4.253 is down.
    Host 192.168.4.254 is down.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹汇川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值