iMisty的技术栈

iMisty的技术栈

Shell编程之条件判断与流程控制

892
2019-05-14

Shell编程之条件判断与流程控制

Shell流程控制语句

条件判断式

  1. 按照文件类型判断
    img
  • 两种判断格式
  • test -e /root/install.log
  • 推荐 :[-e /root/install.log]

操作示例:

    misty@ubuntu:~/MyFile/test$ ls
    canshu1.sh  test1.sh  test2.sh  test3.sh  test4.sh
    # [] 内部两侧需要空格隔开
    misty@ubuntu:~/MyFile/test$ [-e ./test1.sh]
    [-e:未找到命令
    misty@ubuntu:~/MyFile/test$ [ -e ./test1.sh]
    bash: [: 缺少 `]'
    misty@ubuntu:~/MyFile/test$ [ -e ./test1.sh ]
    misty@ubuntu:~/MyFile/test$ echo $?
    0
    # 如果第一条命令正确执行,才会执行第二条命令。如果第二条命令正确执行,那么第三条命令不执行,否则执行第三条命令符号和上一条命令的执行情况有关
    misty@ubuntu:~/MyFile/test$ [ -e ./test1.sh ] && echo "yes" || echo "no"
    yes
    # 第一条命令返回否,第二条命令不执行,结果传递下去,第三条命令会执行
    misty@ubuntu:~/MyFile/test$ [ -e ./test1.shxxx ] && echo "yes" || echo "no"
    no
    # 第一条命令返回否,所以第二条命令执行,第二条命令正确执行,所以第三条命令也会执行
    misty@ubuntu:~/MyFile/test$ [ -e ./test1.shxxx  ] || echo "yes" &&  echo "no"
    yes
    no
  1. 按照文件权限进行判断
    img

    操作示例

   # 首先判断文件是否存在,不存在直接返回否
    # 注意这里只要文件有写权限就会返回真,具体的所有者权限和所属组的权限需要进一步判断(长格式输出截取权限位来判断)
    misty@ubuntu:~/MyFile/test$ [ -w ./test1.sh  ] &&  echo "yes" ||  echo "no"
    yes
  1. 两个文件之间的比较

    img_shell2

    操作实例

# 创建硬链接
  misty@ubuntu:~/MyFile/test$ ln test1.sh tmp_test1.sh
  # 查看inode值判断是否是同一个文件(inode相同)
  misty@ubuntu:~/MyFile/test$ ls -lai
  总用量 32
  14424665 drwxr-xr-x  2 misty misty 4096 6月  29 19:16 .
  31986159 drwxr-xr-x 11 misty misty 4096 6月  22 22:39 ..
  14424669 -rwxr-xr-x  2 misty misty   61 6月  21 14:00 test1.sh
  14424669 -rwxr-xr-x  2 misty misty   61 6月  21 14:00 tmp_test1.sh

  misty@ubuntu:~/MyFile/test$ [ test1.sh -ef tmp_test1.sh ] && echo "yes" || echo "no" 
  yes

两个整数之间的比较

Linux默认内容都是是字符类型,但是加上了数值比较的符号之后当做数字处理

img

操作示例

   misty@ubuntu:~/MyFile/test$ [ 1 -eq 2 ] && echo "yes" || echo "no"
    no
    misty@ubuntu:~/MyFile/test$ [ 1 -ne 2 ] && echo "yes" || echo "no"
    yes
    misty@ubuntu:~/MyFile/test$ [ 1 -gt 2 ] && echo "yes" || echo "no"
    no
    misty@ubuntu:~/MyFile/test$ [ 1 -lt 2 ] && echo "yes" || echo "no"
    yes
    misty@ubuntu:~/MyFile/test$ [ 1 -ge 2 ] && echo "yes" || echo "no"
    no
    misty@ubuntu:~/MyFile/test$ [ 1 -le  2 ] && echo "yes" || echo "no"
    yes
  1. 字符串的判断

注意参数比较一定要记得习惯性加上双引号,虽然一些情况下是一样的,但是,在编写一些复杂的脚本的时候需要可以规避一些问题
img

  misty@ubuntu:~/MyFile/test$ [ -z abc ] && echo "yes" || echo "no"
    no
    misty@ubuntu:~/MyFile/test$ [ -n abc ] && echo "yes" || echo "no"
    yes
    misty@ubuntu:~/MyFile/test$ [ abc ==  abc ] && echo "yes" || echo "no"
    yes
    misty@ubuntu:~/MyFile/test$ [ abc !=  abc ] && echo "yes" || echo "no"
    no
    misty@ubuntu:~/MyFile/test$ a=123
    misty@ubuntu:~/MyFile/test$ b=456
    misty@ubuntu:~/MyFile/test$ [ "$a" == "$b" ] &&  echo yes || echo no  
    no
  1. 多重条件判断

    img

    misty@ubuntu:~/MyFile/test$ aa=11
    # 判断aa是否有值并且大于23
    misty@ubuntu:~/MyFile/test$ [ -n $aa -a $aa -gt 23 ] && echo yes || echo no
    no
    

### 单分支if语句

   shell的语法结构和绝大多数的语言有所不同,用来帮助管理员做系统管理的

```shell
 if [ 条件判断式 ];then
       程序
   fi
   # 或者
   if [ 条件判断式 ]
       then
       程序
   fi        

单分支条件语句的注意点

  • if语句使用fi结尾,和一般语言使用大括号结尾不同

  • [条件判断式]就是使用test命令判断,所以中括号和条件判断式之间必须有空格

  • then后面跟符号条件之后执行的程序,可以放在[]之后,用;分割,也可以写入换行符,就不需要;

    操作实例-查看当前用户是否为root

    #!/bin/bash
    # 这里采用env而不是whoami,是为了防止用户切换获取错误
    # grep行截取 ,cut列截取 -d代表分隔符 -f代表截取第几列
    test=$(env |grep "USER" |cut -d "=" -f 2)
    
    echo "$test"
    if [ "$test" == root ] ;then
            echo "current user is root"
    
    fi
    

操作实例-判断分区的使用率
```shell
    #!/bin/bash
    # 先查看指定磁盘的使用状况,再awk解析出指定列(因为是空格分割不能使用cut),再使用cut去掉%,方便数值比较
    test=$( df -h |grep "/dev/disk1s1" |awk '{print $5}' |cut -d "%" -f 1 )

    echo "$test"
    if [ "$test" -ge 50 ] ;then
            echo "disk is flow 50%"

    fi

双分支if语句

语法结构

    if [ 条件判断式 ]
        then
        条件成立执行的程序
        else
        条件不成立执行的程序
    fi    
操作实例:判断输入的路径时候否为目录
  #!/bin/bash
    # 接收用户输入一个路径
    read -t 30 -p " please input a path " dir

    if [ -d "$dir" ]
       then
            echo "the path is dir"
       else
            echo "the path is not dir"
            
    fi

操作实例:判断Apache服务是否运行

    #!/bin/bash
    # 截取httpd进程,并把结果赋予变量test,因为grep程序也会执行,所以排除grep的截取字段
    test=$(ps aux |grep "httpd" |gtep -v "grep" )

    # 判断变量是否为空
    if [ -n "$test" ]
            then
                 echo "$(date) httpd is ok !"
            else
            # 重新启动Apache
                 /etc/rd.d/init.d/httpd start &> /dev/null
                 echo "$(date) restart httpd "
    fi

这种方式检测,需要避免脚本命名带有关键字,脚本执行的时候,ps会出现脚本的当前进程,因为带有关键字,这种检测方式会出现误判;
更好的方式是判断端口是否被占用来判断程序是否启动

多分支条件判断

语法

  if [ 条件判断式1 ]
        then
            当条件判断式1成立时执行程序1
    elif [ 条件判断式2 ]
        then         
            当条件判断式2成立时执行程序2
    else 
            当所有的条件都不成立时,最后执行此程序
    fi         
操作实例:计算器
#!/bin/bash

 read -t 30 -p "Please input num1:" num1 

 read -t 30 -p "Please input num2:" num2 

 read -t 30 -p "Please input operator:" ope 

 # 判断输入字符是否为空
 if [ -n "$num1" -a -n "$num2" -a -n "$ope" ] 

     then 

 # 定义变量test1和test2 的值为   $(命令)的结果
 # 后续命令的作用是,把 变量test1的值替换成空,如果能够替换成空则说明num1为数字,反之则是字符
         test1=$(echo $num1 | sed 's/[0-9]//g') 

         test2=$(echo $num2 | sed 's/[0-9]//g') 

 # 判断num1和num2为数值,如果test1和test2的值为空则证明num1和num2 为数字
             if [ -z "$test1" -a -z "$test2" ] 

                 then 

                     if [ "$ope" == '+' ] 

                         then 

                             result=$(($num1+$num2)) 

                     elif [ "$ope" == '-' ] 

                         then 

                             result=$(($num1-$num2)) 

                     elif [ "$ope" == '/' ] 

                         then 

                             result=$(($num1 / $num2)) 

                     elif [ "$ope" == '*' ] 

                         then 

                             result=$(($num1*num2)) 

                     else 

                         echo "Error: the input operator is worng, please input +-*/"

                         # 错误码
                         exit 111 

                     fi 

                 else 

                     echo "Error: Please input numbers!"  

                     exit 222 

                 fi 

         echo "$num1 $ope $num2 is $result" 

     else 

         echo "Error: You input null value!" 

         exit 333 

 fi

操作实例:判断用户输入的是什么文件

   #!/bin/bash
    read -t 30 -p  "please input a filename:" file
    # 判断文件是否为空
    if [ -z "$file" ]
         then
            echo "please input content and not't input  null"
            exit 11
    # 判断文件是否存在        
    elif [ ! -e "$file" ]
            then
            echo "  please input file name "
            exit 12
    # 判断是否为文件        
    elif [ -f "$file" ]
            then
            echo  "$file is file"
    # 判断是否为目录        
    elif [ -d "$file" ]
          then
          echo "$file is dir "
    else
         echo "$file is other file"
         
    fi

case 语句

和 `if ...elif ...else`一样都是多分支if语句,不过和if多分支条件语句不同的是,case只判断一种条件关系,而if语句可以判断多种条件关系

case条件语法:

case $变量名 in 
      "value1")
      如果变量值为1,则执行此程序
      ;;
      “value2”
      如果变量值为1,则执行此程序
      ;;
      其他分支:***
      *)
      如果变量的值不满足以上的条件,则执行此程序
      ;;
  esac    

需要注意的是,每个条件结束都要以分号结尾:

操作实例

  #!/bin/bash
    read -t 30 -p "please input your intention " command
    #以关键字case开头
    case $command in
            # condition )的方式
            "yes")
            # 这里跟上具体的业务逻辑
            echo "you input yes!"
            # 这里的;;不可以丢弃
            ;;
            "no")
            echo "you input no!"
            ;;
            # 注意这里的符号不可以加上引号
            *)
            echo "you input $command"
            ;;
    # 一定要带上结尾符号esac        
    esac

for循环

for循环语法
语法一:这种方式若是列举的过多代码量较多,但是符合系统管理需要,配合表达式逻辑很清晰


   for 变量 in 值1 值2 值3...
       do 
           程序
       done   

语法二:

    # 数值运算需要双小括号括起来
    for((初始值;循环控制条件:变量变化))
        do 
        程序
        done

操作实例1:循环输出
 #!/bin/bash
  for i in 1 2 3 4 5 6
  do
          echo $i
  done
操作实例2:批量解压缩

 #!/bin/bash
  cd /root/test
  # 过滤文件,将匹配的文件重定向到日志;
  ls *.tar.gz >ls.log
  ls *.tgz >>ls.log
  # 循环日志中的每一个文件执行解压操作,注意表达式的写法 $(表达式)
  # 当然这里若是只有一个目录和一种压缩格式的话, for i in $(ls *.tar.gz)
  for i in $(cat ls.log)
          do
          #将文件输出到 /dev/null,相当于信息不会显示也不会保存
                  tar -zxvf $i > /dev/null
          done
  # 解压完成删除文件记录
  rm -rf ls.log

操作实例3:从1加到100

 #!/bin/bash
 #从1加到100
 s=0
 # 注意算数运算需要双引号括起来
 for((i=1;i<=100;i=i+1))
 do
         # s=(($s+$i))也可以
         s=$(($s+"$i"))
 done
 echo "the sum of (1+2+...100) is $s"

操作实例4:批量添加用户

 #!/bin/bash
  # 批量添加指定数量的用户
  read -p "Please input user name :"-t 30 name 
  read -p "Please input the number of user :"-t 30 num 
  read -p "Please input user password of user  :"-t 30 pass 
  # 判断参数是否非空,其实 -n 更好不用取反
  if [ ! -z "$name"  -a ! -z "$num" -a  ! -z "$pass"]
      then 
          y=$(echo $num | sed 's/[0-9]//g')
          # 判断输入是否为数字,如果数字替换了为空则为数字
          if [ -z "$y"]
          then 
          for ((i=1;i<$num;i=i+1))
              do 
                  /user/sbin/useradd $name$i &>dev/null

                  # 批量删除用户,只需要这一句话即可,-r连带家目录一起删除 /user/sbin/userdel -r $name$i &>dev/null

                  # 使用echo的返回值作为创建的用户的密码
                  echo $pass | /user/bin/passwd --stdin $name$i &>/dev/null
              done
          fi    
  fi       
  # 查看用户
  cat /etc/passwd

操作实例4:批量删除普通用户

   #!/bin/bash
    # 首先普通用户是可以登陆的包含有/bin/bash,匿名用户不可以登陆包含/sbin/nologin
    # 另外不能删除root,所以需要对排除root ,再以:分割,截取第一列的数据
    users=cat /etc/passwd |grep /bin/bash |grep -v root |cut -d ":" -f 1
    for i in $user
        do 
            # 删除用户以及其家目录的数据 
            userdel -r $i
        done

while循环和until循环

while循环:不定循环,也称作条件循环,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立
循环才会停止
操作实例:从1加到100 while实现
   #!/bin/bash
    # 从1加到100
    i=1
    s=0
    # 当i<=100 则进行循环 
    while [ $i -le 100 ]
    do 
        s=$(($s+$i))
        i=$(($i+1))
    done
    echo "the sum is : $s"
until 循环,和while循环相反,util循环时只要条件判断式不成立则进行循环,并执行循环程序,一旦循环条件成立
则终止循环

操作实例:从1 加到100 until实现
#!/bin/bash
 # 从1加到100
 i=1
 s=0
 # 直到i>100则终止循环
 until [ $i -gt 100 ]
 do 
     s=$(($s+$i))
     i=$(($i+1))

 done
 echo "the sum is : $s"