Shell编程中的条件判断与流程控制

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: Shell编程中的条件判断与流程控制

【1】条件判断

① 按照文件类型进行判断

测试选项 作 用
-b 文件 判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
-c文件 判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
-d 文件 判断该文件是否存在,并且是否为目录文件(是目录为真)
-e 文件 判断该文件是否存在(存在为真)
-f 文件 判断该文件是否存在,并且是否为普通文件(是普通文件为真)
-L 文件 判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
-p 文件 判断该文件是否存在,并且是否为管道文件(是管道文件为真)
-s 文件 判断该文件是否存在,并且是否为非空(非空为真)
-S 文件 判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)

判断文件是否存在:

[root@localhost shell]# [ -e /home/shell ]
[root@localhost shell]# echo $?
0
#输出为0 表示存在

test -e /home/shell 等同于 [ -e /home/shell ] 两种格式写法。

判断/home/shell是否为目录:

#这里用了&& ||
[root@localhost shell]# [ -d /home/shell ] && echo "yes" || echo "no"
yes

② 按照文件权限进行判断

测试选项 作 用
-r 文件 判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真)
-w文件 判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真)
-x 文件 判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真)
-u 文件 判断该文件是否存在,并且是否该文件拥有SUID权限(有SUID权限为真)
-g 文件 判断该文件是否存在,并且是否该文件拥有SGID权限(有SGID权限为真)
-k 文件 判断该文件是否存在,并且是否该文件拥有SBit权限(有SBit权限为真)

测试实例:

[root@localhost shell]# [ -w student.txt ] && echo "yes" || echo "no"
yes

③ 两个文件之间进行比较

测试选项 作 用
文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新(如果新则为真)
文件1 -ot 文件2 判断文件1的修改时间是否比文件2的旧(如果旧则为真)
文件1 -ef 文件2 判断文件1是否和文件2的Inode号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法


如下测试硬链:

#创建硬链
[root@localhost shell]# ln ./student.txt student1.txt
#进行测试
[root@localhost shell]# [ student.txt -ef student1.txt ] && echo "yes" || echo "no"
yes
#创建软连
[root@localhost shell]ln -s student.txt student3.txt
# lrwxrwxrwx 1 root root  11 Jul 20 12:10 student3.txt -> student.txt
[root@localhost shell]# [ student.txt -ef student3.txt ] && echo "yes" || echo "no"
yes
#判断是否符号链接文件
[root@localhost shell]# [  -L student3.txt ] && echo "yes" || echo "no"
yes
#判断是否符号链接文件
[root@localhost shell]# [  -L student1.txt ] && echo "yes" || echo "no"
no

关于两个文件比较,还可以之间使用diff命令,如下所示:

[root@localhost shell]# diff student.txt student2.txt
2a3
> 中    Liming  82      95      86      87.66

④ 两个整数之间用来比较

测试选项 作 用
整数1 -eq 整数2 判断整数1是否和整数2相等(相等为真)
整数1 -ne 整数2 判断整数1是否和整数2不相等(不相等为真)
整数1 -gt 整数2 判断整数1是否大于整数2(大于为真)
整数1 -lt 整数2 判断整数1是否小于整数2(小于位置)
整数1 -ge 整数2 判断整数1是否大于等于整数2(大于等于为真)
整数1 -le 整数2 判断整数1是否小于等于整数2(小于等于为真)


测试实例如下:

[root@localhost shell]# [ 23 -ge 22 ] && echo "yes" || echo "no"
yes

⑤ 字符串的判断

测试选项 作 用
-z 字符串 判断字符串是否为空(为空返回真)
-n 字符串 判断字符串是否为非空(非空返回真)
字串1 == 字串2 判断字符串1是否和字符串2相等(相等返回真)
字串1 != 字串2 判断字符串1是否和字符串2不相等(不相等返回真)

测试实例如下:

[root@localhost shell]# [  -z 22 ] && echo "yes" || echo "no"
no
[root@localhost shell]# [  -z "" ] && echo "yes" || echo "no"
yes
#给变量a b赋值
[root@localhost shell]# a=1
[root@localhost shell]# b=2
#注意==左右两边的空格
[root@localhost shell]# [  "$a" == "$b" ] && echo "yes" || echo "no"
no

⑥ 多重条件判断

测试选项 作 用
判断1 -a 判断2 逻辑与,判断1和判断2都成立,最终的结果才为真
判断1 -o 判断2 逻辑或,判断1和判断2有一个成立,最终的结果就为真
!判断 逻辑非,使原始的判断式取反

测试实例如下:

#判断a是否非空且a==b
[root@localhost shell]# [ -n "$a" -a  "$a" == "$b" ] && echo "yes" || echo "no"
no
[root@localhost shell]# [ -n "$a" -a  "$a" -gt 0 ] && echo "yes" || echo "no"
yes
#逻辑非测试
[root@localhost shell]# [ ! -n "$a" ] && echo "yes" || echo "no"
no

【2】流程控制之if条件判断

① 单分支if条件语句

单分支条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情都不做。语法如下:

if [  条件判断式  ];then
    程序
fi

单分支条件语句需要注意几个点:

  • if语句使用fi结尾,和一般语言使用大括号结尾不同
  • [ 条件判断式 ]就是使用test命令判断,所以中括号和条件判断式之间必须有空格
  • then后面跟符合条件之后执行的程序,可以放在[]之后,用“;”分割。也可以换行写入,就不需要“;”了,比如单分支if语句还可以这样写:
if [ 条件判断式 ]
  then
    程序
fi

如下实例判断磁盘空间使用率$(df -h | grep "/dev/sda1" | awk '{print $5}' | cut -d "%" -f1)可得到磁盘使用率整数部分

[root@localhost shell]# vim if1.sh
#/bin/bash
rate=$(df -h | grep "/dev/sda1" | awk '{print $5}' | cut -d "%" -f1)
if [ $rate -le 80 ];then
        echo "Releax! /dev/sda1 is empty!!"
fi
[root@localhost shell]# ./if1.sh
Releax! /dev/sda1 is empty!!


② 双分支if条件语句

语法格式如下:

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


如下数据备份实例:

#!/bin/bash
#同步系统时间
ntpdate asia.pool.ntp.org &>/dev/null
#把当前系统时间按照“年月日”格式赋予变量date
date=$(date +%y%m%d)
#统计mysql数据库的大小,并把大小赋予size变量
size=$(du -sh /var/lib/mysql)
if [ -d /tmp/dbbak ]
  #判断备份目录是否存在,是否为目录   #如果判断为真,执行以下脚本
  then
    #把当前日期写入临时文件
    echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
    #把数据库大小写入临时文件
    echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
    #进入备份目录
    cd /tmp/dbbak
    #打包压缩数据库与临时文件,把所有输出丢入垃圾箱(不想看到任何输出)
    tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
    #删除临时文件
    rm -rf /tmp/dbbak/dbinfo.txt
else
    #如果判断为假,则建立备份目录
    mkdir /tmp/dbbak
    #把日期和数据库大小保存到临时文件
    echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
    echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
    #压缩备份数据库与临时文件
    cd /tmp/dbbak
    tar -zcf mysql-lib-$date.tar.gz dbinfo.txt /var/lib/mysql &>/dev/null
    #删除临时文件
    rm -rf /tmp/dbbak/dbinfo.txt
fi

③ 多分支if条件语句

语法格式如下:

if [ 条件判断式1 ]
  then
    当条件判断式1成立时,执行程序1
elif [ 条件判断式2 ]
    then
    当条件判断式2成立时,执行程序2
    …省略更多条件…
else
    当所有条件都不成立时,最后执行此程序
fi

判断用户输入的名字是什么类型文件实例如下:

#/bin/bash
read -p "Please input a filename: " file
#判断file变量是否为空
if [ -z "$file" ]
        then
                echo "Error,please input a filename"
         #退出程序,并返回值为1(把返回值赋予变量$?)
        exit 1
#判断file的值是否存在
elif [ ! -e "$file" ]
        then
                echo "Your input is not a file!"
        exit 2
#判断file的值是否为普通文件
elif [ -f "$file"  ]
        then
                echo "$file is a regulare file!"
#判断file的值是否为目录文件
elif [ -d "$file"  ]
        then
                echo "$file is a directory"
#如果以上判断都不是,则执行程序5
else
        echo "$file is an other file!"
fi
[root@bogon shell]# ./if-elif.sh
Please input a filename: test1.txt
test1.txt is a regulare file!

完善版的四则运算计算器:

#!/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
                                value=$(( $num1 + $num2 ))
                #如果是加号则执行加法运算
                        elif [ "$ope" == '-' ]
                                then
                                value=$(( $num1 - $num2 ))
                #如果是减号,则执行减法运算
                        elif [ "$ope"  == '*' ]
                                then
                                value=$(( $num1 * $num2  ))
                        elif [ "$ope" == '/' ]
                                then
                                value=$(( $num1 / $num2 ))
                        else
                                echo "Please enter a valid symbol"
                                #如果运算符不匹配,提示输入有效的符号
                                exit 10
                #并退出程序,返回错误代码10
                        fi
                else
        #如果test1和test2不为空,说明num1和num2 不是数字
                        echo "Please enter a valid value"
                        #则提示输入有效的数值
                        exit 11
            #并退出程序,返回错误代码11
        fi
else
        echo "qing shuru neirong"
        exit 12 
fi
echo " $num1 $ope $num2 : $value"
#输出数值运算的结果


【3】流程控制之case条件判断

case语句和if…elif…else语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。case语句语法如下:

case $变量名 in
  "值1")
  如果变量的值等于值1,则执行程序1
  ;;
  "值2")
  如果变量的值等于值2,则执行程序2
  ;;
  …省略其他分支…
  *)
  如果变量的值都不是以上的值,则执行此程序
  ;;
esac

这个语句需要注意以下内容:


case语句,会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序,如果数值不符,则依次比较下一个值。如果所有的值都不符合,则执行“*)”(“*”代表所有其他值)中的程序。

case语句以“case”开头,以“esac”结尾(就是case倒转)。

每一个分支程序之后要通过“;;”双分号结尾,代表该程序段结束。

测试实例如下:

[root@localhost shell]# cat case.sh
#!/bin/bash
read -p "Please choose yes/no: " -t 30 cho
case "$cho" in
        "yes")
                echo "your choose is yes"
                ;;
        "no")
                echo "your choose is no"
                ;;
        *)
                echo "your choose is error"
                ;;
esac
[root@localhost shell]# ./case.sh
Please choose yes/no: yes
your choose is yes


【4】流程控制之for循环

for循环是固定循环,也就是在循环时已经知道需要进行几次的循环,有时也把for循环称为计数循环。

for的语法有如下两种。语法一如下:

#语法一
for 变量 in 值1 值2 值3…
  do
    程序
  done


这种语法中for循环的次数,取决于in后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。也就是说,假设in后面有三个值,for会循环三次,第一次循环会把值1赋予变量,第二次循环会把值2赋予变量,以此类推。


实例如下:

[root@bogon shell]# ./for.sh
this time is morning
this time is noon
this time is afternoon
this time is evening
[root@bogon shell]# cat for.sh
#!/bin/bash
for time in morning noon afternoon evening
        do
                echo "this time is $time"
        done


语法二如下:

for (( 初始值;循环控制条件;变量变化 ))
  do
    程序
  done


语法二中需要注意:

  • 初始值:在循环开始时,需要给某个变量赋予初始值,如i=1;
  • 循环控制条件:用于指定变量循环的次数,如i<=100,则只要i的值小于等于100,循环就会继续;
  • 变量变化:每次循环之后,变量该如何变化,如i=i+1。代表每次循环之后,变量i的值都加1。


如求和1-100:

[root@bogon shell]# vi for2.sh
#!/bin/bash
s=0
for (( i=1;i<=100;i++  ))
        do
                s=$(( $s+$i  ))
        done
echo "the sum of 1+2+...+100 is:$s"
[root@bogon shell]# ./for2.sh
the sum of 1+2+...+100 is:5050


如下批量添加指定数量的用户:

[root@localhost ~]# vi useradd.sh
#!/bin/bash
read -p "Please input user name: " -t 30 name
#让用户输入用户名,把输入保存入变量name
read -p "Please input the number of users: " -t 30 num
#让用户输入添加用户的数量,把输入保存入变量num
read -p "Please input the password of users: " -t 30 pass
#让用户输入初始密码,把输入保存如变量pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
  #判断三个变量不为空
  then
  y=$(echo $num | sed 's/[0-9]//g')
  #定义变量的值为后续命令的结果
  #后续命令作用是,把变量num的值替换为空。如果能替换为空,证明num的值为数字
  #如果不能替换为空,证明num的值为非数字。用这种方法判断变量num的值为数字
  if [ -z "$y" ]
  #如果变量y的值为空,证明num变量是数字
    then
      for (( i=1;i<=$num;i=i+1 ))
      #循环num变量指定的次数
        do
          /usr/sbin/useradd $name$i &>/dev/null
          #添加用户,用户名为变量name的值加变量i的数字
          echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
          #给用户设定初始密码为变量pass的值
          chage -d 0 $name$i &>/dev/null
          #强制用户登录后修改密码
        done
  fi
fi
[root@bogon shell]# ./useradd.sh
Please input user name: jane
Please input the number of users: 1
Please input the password of users: 123456
[root@bogon shell]# cat /etc/passwd|grep "jane"
jane:x:1000:1000:jane:/home/jane:/bin/bash
jane1:x:1001:1001::/home/jane1:/bin/bash

如下批量删除用户:

#!/bin/bash
#批量删除用户
user=$(cat /etc/passwd | grep "/bin/bash"|grep -v "root"|cut -d ":" -f 1)
#读取用户信息文件,提取可以登录用户,取消root用户,截取第一列用户名
for i in $user
  #循环,有多少个普通用户,循环多少次
  do
    userdel -r $i
    #每次循环,删除指定普通用户 -r表示家目录一同删除
  done

【5】流程控制之while循环

语法格式如下:

#注意空格
while  [ 条件判断式 ]
  do
    程序
  done

对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。

如下求和1-100:

[root@bogon shell]# vim while.sh
#!/bin/bash
s=0
i=1
while [ $i -le 100 ]
        do
                s=$(( $s+$i ))
                i=$(( $i+1 ))
        done
echo "the sum 1+2+...+100 is :$s"
[root@bogon shell]# ./while.sh
the sum 1+2+...+100 is :5050

【6】流程控制之until循环

再来看看until循环,和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

语法格式如下:

until  [  条件判断式  ]
  do
    程序
  done

求和1-100:

#!/bin/bash
s=0
i=1;
until [ $i -gt 100 ]
        do
                s=$(( $s+$i ))
                #加上这句将会变成求1-100内的偶数
               # i=$(( $i+1 ))
        done
echo "the sum 1+2+...+100 is :$s"
[root@bogon shell]# ./until.sh
the sum 1+2+...+100 is :5050

【7】特殊流程控制语句

① exit语句


系统是有exit命令的,用于退出当前用户的登录状态。可是在Shell脚本中,exit语句是用来退出当前脚本的。也就是说,在Shell脚本中,只要碰到了exit语句,后续的程序就不再执行,而直接退出脚本。

exit的语法如下:

exit [返回值]

如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可以通过查询$?这个变量,来查看返回值。如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit语句之前,最后执行的一条命令的返回值。


测试实例如下:

[root@bogon shell]# vim exit.sh
#!/bin/bash
read -p "Please input a number:" -t 30 num
#如果变量num的值是数字,则把num的值替换为空,否则不替换
#把替换之后的值赋予变量y
y=$( echo $num|sed 's/[0-9]//g' )
#判断变量y的值如果不为空,输出报错信息,退出脚本,退出返回值为18
[ -n '$y' ] && echo "Error,please input a number !" && exit 18
echo "the number is :$num"
[root@bogon shell]# ./exit.sh
Please input a number:kk
Error,please input a number !
[root@bogon shell]# echo $?
18


② break语句

当程序执行到break语句时,会结束整个当前循环。而continue语句也是结束循环的语句,不过continue语句单次当前循环,而下次循环会继续。

测试如下:

[root@localhost ~]# vi sh/break.sh
#!/bin/bash
#演示break跳出循环
for (( i=1;i<=10;i=i+1 ))
#循环十次
  do
    if [ "$i" -eq 4 ]
    #如果变量i的值等于4
      then
        break
        #退出整个循环
    fi
    echo $i
    #输出变量i的值
  done


执行下这个脚本,因为一旦变量i的值等于4,整个循环都会跳出,所以只能循环三次:

[root@localhost ~]# chmod 755 break.sh
[root@localhost ~]# sh/break.sh
1
2
3


③ continue语句

continue也是结束流程控制的语句。如果在循环中,continue语句只会结束单次当前循环,然后继续下次循环。

[root@localhost ~]# vi sh/continue.sh
#!/bin/bash
#演示continue语句
for (( i=1;i<=10;i=i+1 ))
  do
    if [ "$i" -eq 4 ]
      then
        continue
        #退出语句换成continue
    fi
    echo $i
  done
[root@localhost ~]# chmod 755 continue.sh
#赋予执行权限
[root@localhost ~]# ./continue.sh
1
2
3
#少了4这个输出
5 
6
7
8
9
10

continue只会退出单次循环,所以并不影响后续的循环,所以只会少4的输出。这个例子和break的例子做个比较,应该可以更清楚的说明break和continue的区别。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
16天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
1月前
|
Shell
Shell编程(下)
Shell编程(下)
88 1
|
1月前
|
Shell Linux Windows
Shell编程(上)
Shell编程(上)
39 1
|
1月前
|
Java Shell 网络安全
Shell 流程控制
10月更文挑战第4天
34 2
|
1月前
|
Shell Linux 开发工具
|
1月前
|
监控 Unix Shell
shell脚本编程学习
【10月更文挑战第1天】shell脚本编程
62 12
|
2月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
网络协议 Shell Linux
【Linux】shell编程基础(超详细,入门看这一篇就够了)(下)
【Linux】shell编程基础(超详细,入门看这一篇就够了)(下)
106 0
|
6月前
|
存储 Shell C语言
shell脚本 编程 变量 基本入门(详解)
shell脚本 编程 变量 基本入门(详解)