首页 > 编程笔记 > Linux笔记 阅读:35

Shell if else语句用法详解(附带实例)

程序语言的流程控制主要包含以下三大类:
请大家注意,shell 语句是顺序执行的,而且可以直接使用 Linux 的命令,因此更加利于系统管理和维护。

if 语句能够在判断成立或不成立之后执行不同的操作。我们可以在脚本中定义,当某些条件成立时执行对应的 A 程序,当条件未成立时执行 B 程序。我们还可以在脚本中给出多种条件,只要满足了其中的某个条件,就执行相应的某些程序。

Shell if单分支条件语句

单分支 if 条件语句的格式相对简单,只有一个判断条件,只有判断条件成立时才执行相应程序,否则结束判断。

单分支 if 条件语句的执行过程如下图所示:


图 1 单分支if条件语句的执行过程

单分支 if 条件语句的语法如下:
if [ 条件判断式 ];then
    程序
fi
在使用单分支 if 条件语句时需要注意以下几点:
if [ 条件判断式 ]
then
    程序
fi

单分支 if 条件语句非常简单,但是千万不要小看它,这是流程控制语句最基本的语法。而且在实现 Linux 管理时,我们的管理脚本一般都不复杂,使用单分支 if 条件语句的概率还是很高的。

例如,~/.bashrc 文件中就存在单分支 if 条件语句:
[root@localhost ~]# cat ~/.bashrc
...省略部分文件内容...
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi
...省略部分文件内容...
在 .bashrc 文件中使用单分支 if 条件语句判断是否存在 /etc/bashrc 文件,如果 /etc/bashrc 文件存在,就使用“.”让/etc/bashrc文件在当前 shell 中生效。

接下来使用单分支 if 条件语句编辑一个 shell 脚本,例如,我想通过脚本判断根分区的使用率是否超过 80%,如果超过 80% 就向管理员报警,请注意,那么脚本可以这样写:
[root@localhost ~]# df -h
#查看服务器的分区状况

文件系统      容量   已用    可用    已用%%  挂载点
/dev/sda3      20G    1.8G    17G      10%    /
tmpfs         306M      0     306M      0%    /dev/shm
/dev/sda1      194M     26M    158M      15%    /boot
/dev/sr0       3.5G    3.5G      0     100%    /mnt/cdrom

[root@localhost ~]# vim /root/if1.sh
#!/bin/bash
#统计根分区的使用率

rate=$(df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" -f1)
#把根分区使用率作为变量赋予变量 rate

if [ $rate -ge 80 ]
#判断变量 rate 的值,如果大于等于 80,就执行 then 程序
then
    echo "Warning!/dev/sda3 is full!!!"
    #打印警告信息。在实际工作中,也可以向管理员发送邮件
fi
其实,这个脚本最重要的地方是“rate=$(df-h|grep"/dev/sda3"|awk'{print$5}'|cut-d"%"-f1)”,我们来分析一下这条命令:
这条命令的执行结果如下:
[root@localhost ~]# df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" -f1
10

提取出根分区的使用率后,判断这个数字是否大于等于 80,如果大于等于 80 就报警。至于报警信息,我们可以通过脚本直接输出到屏幕上。在实际工作中,因为服务器屏幕并不是24小时都有人值守的,所以也可以给管理员发送邮件,用于报警。

在脚本写好之后,就可以利用系统定时任务,让这个脚本每天或每几天执行一次,实现自动检测硬盘剩余空间。后续系统管理的脚本,如果需要重复执行,那么也可以使用系统定时任务来实现。

Shell双分支if条件语句

在双分支 if 条件语句中,当条件判断式成立时,就执行某个程序;当条件判断式不成立时,就执行另一个程序。

与单分支 if 条件语句相比,双分支 if 条件语句同样只有一个条件判断式。不同于单分支 if 条件语句,在执行双分支 if 条件语句之后,无论条件判断式成立或不成立,都有对应的执行程序,如下图所示。


图 2 双分支if条件语句的执行过程

语法如下:
if [ 条件判断式 ]
then
    当条件判断式成立时,执行的程序
else
    当条件判断式不成立时,执行的另一个程序
fi

例如,使用双分支 if 条件语句来进行目录判断:
#!/bin/bash
read -t 30 -p "Please input a directory:" dir
#通过 read 语句接收键盘的输入,并存入变量 dir

if [ -d $dir ]
    #测试 $dir 中的内容是否是一个目录
    then
        echo "yes"
        #如果是一个目录,就输出 yes
    else
        echo "no"
        #如果不是一个目录,就输出 no
fi
解释一下脚本思路,首先通过 read 语句接收键盘输入。read 输出提示“Please input a directory:”,将键盘输入的字符串赋值给变量 dir。

接下来,使用双分支 if 条件语句判断变量 dir 的值是否为目录。假设判断成立,就执行 then 之后的程序,也就是 echo“yes”。假设判断不成立,就执行 else 之后的程序,也就是echo“no”。

再例如,在工作中,服务器上的服务可能会宕机。如果对服务器的监控不力,就会造成服务器上的服务宕机而管理员却不知道的情况。这时可以编写一个脚本来监听本机的服务,如果服务停止或宕机,就可以自动重启这些服务。我们拿 Apache 服务来举例:
[root@localhost ~]# vim /root/autostart.sh
#!/bin/bash
#判断 Apache 服务是否运行,如果没有运行就启动服务并记录启动服务时间,如果服务正常运行就只进行记录

port=$(nmap -sT 192.168.4.210 | grep tcp | grep http | awk '{print $2}')
#使用 nmap 命令扫描服务器,并截取 Apache 服务的状态,赋予变量 port

if [ "$port" == "open" ]
#如果变量 port 的值是 "open"
then
    echo "$(date) httpd is ok!" >> /tmp/autostart-acc.log
    #就证明 Apache 服务正常运行,在正确日志中写入一句话即可
else
    systemctl start httpd.service &>/dev/null
    #否则证明 Apache 服务没有启动,启动 Apache 服务
    echo "$(date) restart httpd !!!" >> /tmp/autostart-err.log
    #并在错误日志中记录自动启动 Apache 服务的时间
fi
解释一下脚本思路,在这个例子中,关键点是如何判断 Apache 服务是否启动了。如果使用 netstat-tlun 命令或 ps aux 命令,就只能判断本机的 Apache 服务是否启动,而不能判断远程服务器是否启动了 Apache 服务。而如果使用 telnet 命令,那么虽然可以探测远程服务器的80端口是否启动,但是要想退出探测界面,还需要执行人机交互,非常麻烦。

因此,我们使用 nmap 端口扫描命令,如果系统中默认没有 nmap 端口,那么可以通过 dnf 安装,包名为 nmap。nmap 命令的格式如下:
[root@localhost ~]# nmap -sT 域名或 IP
选项:
这条命令的执行结果如下:
[root@localhost ~]# nmap -sT 192.168.4.210
#可以看到,这台服务器开启了如下服务

Starting Nmap 7.92 ( http://nmap.org ) at 2024-03-26 16:12 CST
Nmap scan report for 192.168.4.210
Host is up (0.0010s latency).
Not shown: 994 closed ports

PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http    <--Apache 服务的状态是 open
111/tcp open  rpcbind
139/tcp open  netbios-ssn
445/tcp open  microsoft-ds
3306/tcp open  mysql

Nmap done: 1 IP address (1 host up) scanned in 0.49 seconds

了解了 nmap 命令的用法后,我们在脚本中使用的命令就是为了截取 HTTP 的状态,只要状态是“open”就证明 Apache 服务启动正常,否则证明 Apache 服务启动错误。来看看脚本中命令的执行结果:
[root@localhost ~]# nmap -sT 192.168.4.210 | grep tcp | grep http | awk '{print $2}'
###首先指定计算机,先提取包含 tcp 的行,再提取包含 httpd 的行,截取第二列
open
#把截取的值赋予变量 port

Shell多分支if条件语句

在多分支 if 条件语句中,可以使用多个条件判断式,多个条件判断式会逐一进行判断。若判断成立则执行对应程序,对应程序执行完成后结束当前整体 if 判断;若判断不成立则继续逐个使用执行条件判断式进行判断,如果所有条件判断式均未判断成立,就执行 else 后的语句,else 语句执行后,整体 if 判断结束。

多分支 if 条件语句的执行过程如下图所示:


图 3 多分支if条件语句的执行过程

语法如下:
if[ 条件判断式 1 ]
    then
        程序 1
elif[ 条件判断式 2 ]
    then
        程序 2
...省略更多条件...
else
    上述所有条件均未成立执行此程序
fi

例如,使用多分支 if 条件语句来判断用户输入的是一个文件还是一个目录,具体如下:
[root@localhost ~]# cat /root/if-elif.sh
#!/bin/bash
read -p "Please input a filename:" file
#接收键盘输入,赋值给变量 file
if[ -z "$file" ]
    #判断 file 变量值是否为空
then
    echo "error,Please input a file name!"
    #如果 file 变量值为空就输出错误提示信息
elif[ -f "$file" ]
    #判断 file 变量值是否为普通文件
then
    echo "$file is a regular file!"
    #如果 file 变量值为普通文件就输出提示
elif[ -d "$file" ]
    #判断 file 变量值是否为目录
then
    echo "$file is a directory!"
    #如果 file 变量值为目录就输出提示
elif[ -e "$file" ]
    #判断 file 变量值是否存在
then
    echo "$file not regular file or directory!"
    #file 变量值为存在的文件,说明文件存在,但文件类型既不是普通文件也不是目录文件
else
    echo "$file file does not exist!"
    #如果以上所有判断不成立,就执行 else 后代码
fi
解释一下脚本思路,在脚本执行后,再通过执行 read 语句输出提示信息,并将用户键盘输入的字符串赋值给变量file。

在多分支 if 条件语句中:
注意,在编辑多分支 if 条件语句时,我们使用的多个条件判断式会按照编辑顺序从上到下进行判断,哪个判断成立就执行相对应的 then 中的程序,程序执行后就结束整体 if 判断。因此,在上面的多分支if条件语句中,假设我们把文件是否存在的判断写在普通文件和目录判断之前,就永远不可能执行普通文件和目录的判断,因为在判断文件存在成立后就会执行相应程序,程序执行后就会退出 if 判断,并不会进行后续条件判断。

再例如,在之前的位置参数变量和 read 语句中,我们曾经多次编辑过四则运算的计算器,现在把 if 判断加入计算,就可以用于判断 read 语句的值是否为空,还可以判断要用来计算的运算符号。
[root@localhost ~]# vim /root/sum.sh
#!/bin/bash
#字符界面加减乘除计算器
read -t 30 -p "Please input num1:" num1
read -t 30 -p "Please input num2:" num2
#通过 read 语句接收要计算的数值,并赋予变量 num1 和 num2
read -t 30 -p "Please input a operator:" ope
#通过 read 语句接收要计算的符号,并赋予变量 ope

if [ -n "$num1" -a -n "$num2" -a -n "$ope" ]
    #第一层判断,用来保证变量 num1、num2 和 ope 中都有值
then
    test1=$(echo $num1 | sed 's/[0-9]//g')
    test2=$(echo $num2 | sed 's/[0-9]//g')
    #定义变量 test1 和 test2 的值为 $(命令) 的结果
    #后续命令的作用是把变量 test1 的值替换为空。如果能替换为空,就证明变量 num1 的值为数字
    #如果不能替换为空,就证明变量 num1 的值为非数字。我们使用这种方法判断得出变量 num1 的值为数字
    #用同样的方法测试变量 test2

    if [ -z "$test1" -a -z "$test2" ]
        #第二层判断,用来保证变量 num1 和 num2 的值为数字
        #如果变量 test1 和 test2 的值为空,就证明变量 num1 和 num2 的值为数字
    then
        #如果变量 test1 和 test2 的值为数字,就执行以下命令
        if [ "$ope" == '+' ]
            #第三层判断,用来确认运算符
            #测试变量 $ope 中是什么运算符
        then
            sum=$( ( $num1 + $num2 ))
            #如果是加号,就执行加法运算
        elif [ "$ope" == '-' ]
            then
            sum=$( ( $num1 - $num2 ))
            #如果是减号,就执行减法运算
        elif [ "$ope" == '*' ]
            then
            sum=$( ( $num1 * $num2 ))
        elif [ "$ope" == '/' ]
            then
            sum=$( ( $num1 / $num2 ))
        else
            echo "Please enter a valid symbol"
            #如果运算符不匹配,就提示输入有效的符号
        fi
    else
        #如果变量 test1 和 test2 的值不为数字
        echo "Please enter a valid value"
        #就提示输入有效的数值
    fi
else
    #如果变量 num1、num2 和 ope 中没有内容
这个脚本的逻辑比较复杂,出现了三层判断。因为我们很难控制用户到底输入了什么内容,所以必须加入必要的判断,以此保证程序正确运行:
通过第三层判断运算符我们可以看到,对于 if 条件判断式来说,其可以进行类型判断,如文件类型的判断、文件权限的判断及数字大小的判断,也可以对某些具体的指定字符串进行判断。

执行一下这个脚本:
[root@localhost ~]# ./root/sum.sh
Please input num1: y
Please input num2: u
#如果没有输入数字
Please input a operator: +
Please enter a valid value
#就报错,请输入正确的数值

[root@localhost ~]# ./sh/sum.sh
Please input num1: 6
Please input num2: 9
Please input a operator: k
#如果运算符输入错误
Please enter a valid symbol
#就报错,请输入有效的符号

[root@localhost ~]# ./sh/sum.sh
Please input num1: 6
Please input num2: 9
Please input a operator: *
6 * 9 : 54
#如果输入都正确,脚本就可以正确地进行运算

相关文章