• 02-shell的流程控制


    流程控制语句内容介绍
    • 1. 流程控制语句if基本概述
    • 2. 流程控制语句if文件比较
    • 3. 流程控制语句if整数比较
    • 4. 流程控制语句if字符比较
    • 5. 流程控制语句if正则比较
    • 6. 流程控制语句if场景示例
    • 7. 流程控制语句case基本概述
    • 8. 流程控制语句case场景示例
    • 9. 交互式脚本expect场景示例
     
     1、流程控制语句if基本概述
    1. 单分支结构
    if [];then
          echo ""
    fi
     
    1. 双分支结构
    if grep "$1" /etc/passwd >/dev/null;then
           echo "ok"
       else
           echo "error"
    fi
     
    1. 多分支结构
    if [];then
         echo ""
    elif [];then
         echo ""
    elif [];then
         echo ""
       else
         exit
    fi
     
    示例:判断是否存在某用户和家目录
    [root@shell scripts]# vim user_home.sh
    #!/bin/bash
    #判断用户和用户家目录是否存在
    read -p "请输入一个用户名:" user
    if grep $user /etc/passwd >/dev/null;then
            echo "该系统上存在用户$user"
    elif ls -d /home/$user >/dev/null;then
            echo "该系统上不存在用户$user"
            echo "但该系统上存在用户$user的家目录"
       else
            echo "该系统上不存在用户$user和$user家目录"
    fi
     
    2、 流程控制语句if文件比较
    参数
    说明
    示例
    -e
    如果文件或目录存在则为真
    [ -e file]
    -s
    如果文件存在且至少有一个字符则为真
    [ -s file]
    -d
    如果文件存在且为目录则为真
    [ -d file]
    -f
    如果文件存在且为普通文件则为真
    [ -f file]
    -r
    如果文件存在且可读则为真
    [ -r file]
    -w
    如果文件存在且可写则为真
    [ -w file]
    -x
    如果文件存在且可执行则为真
    [ -x file]
     
     
    示例:判断/etc/hosts文件是否存在
    if [ -f /etc/hosts ];then
       echo "ok"
    else
       echo "err"
    fi
    [root@shell scripts]# dir=/etc/;[ -d /etc/hosts ] && echo "ok" || echo "err"
     
    应用场景:手动输入需要备份的库,备份MySQL数据
       思路:1)提示用户输入库名称      read -p
                 2)  如果用户输入数据库名称,则执行mysqldump命令备份
                 3)指定备份目录          /backup/mysql
    [root@shell scripts]# vim mysqldump.sh
    #!/bin/bash
    #手动输入需要备份的库,备份MySQL数据
     
    DestPath=/backup/mysql
    User=root
    Pass=123456
    #1. 判断备份目录是否存在,如果不存在则创建
    [ -d $DestPath ] || mkdir -p $DestPath
     
    #2. 手动输入数据库名称
    read -p "请输入数据库名称:" DB
     
    #3. 备份指定的MySQL库的数据
    /usr/bin/mysqldump -u$User -p$Pass --single-transaction -R -B $DB >$DestPath/${DB}_$(date +%F).sql
     
    if [ $? -eq 0 ];then
       echo "--------$DB备份完成----------"
    fi
     
    3、流程控制语句if数值比较
    参数
    说明
    示例
    -eq
    等于则条件为真
    [ $? -eq 0 ]
    -ne
    不等于则条件为真
    [ $? -ne 0 ]
    -gt
    大于则条件为真
    [ $? -gt 0 ]
    -lt
    小于则条件为真
    [ $? -lt 0 ]
    -ge
    大于等于则条件为真
    [ $? -ge 0 ]
    -le
    小于等于则条件为真
    [ $? -le 0 ]
    示例:编写一个脚本检测服务是否运行
       1)如何判断我们的服务是否运行    systemctl status sshd
       2)判断前者命令执行是否成功,成功则输出运行,失败输出程序没有运行
    [root@shell scripts]# vim systemctl.sh
    #!/bin/bash
    #  $#:判断位置参数的个数
    #  $0:当前脚本的名字
    #  $1:定义要传的参数
    if [ $# -ne 1 ];then
           echo $#
           echo "请输入一个服务名称,示例 sh $0 [nginx|httpd|sshd...]"
           exit
    fi
     
    systemctl status "$1" &>/dev/null
    rc=$?
    if [ $rc -eq 0 ];then
           echo "$1 服务正常运行"
    elif [ $rc -eq 4 ];then
           echo "$1 没有这个服务"
       else
           echo "$1 服务没有运行"
    fi
     
    场景实践,查看磁盘当前的使用状态,如果使用超过80%则发邮件报警
    [root@shell scripts]# vim disk_use.sh
    #!/bin/bash
    #监控磁盘使用情况,并发送告警邮件
     
    Disk_Free=$(df -h | grep "/$"|awk '{print $5}'|awk -F '%' '{print $1}')
    if [ $Disk_Free -ge 80 ];then
             echo "磁盘使用已超过80%,当前使用率为${Disk_Free}%" >/tmp/disk.txt
             mail -s "磁盘使用已超标,请注意!!!" 276715936@qq.com </tmp/disk.txt
         else
             echo "当前使用率为${Disk_Free}%"
    fi
    -F                 设置输入域分隔符
    $NF                表示最后一列
    $(NF-1)            表示倒数第二列
    NR                 表示行号,第几行
    $0                 表示显示整行内容
    $1                 表示第1列 
    [root@web ~]# cat index.txt
    http://www.baidu.com/index.html
     
    [root@web ~]# cat index.txt | awk -F '/' '{print $3}'
    www.baidu.com
    [root@web ~]# df -h | awk 'NR==1,NR==2 {print $0}'
    Filesystem      Size  Used Avail Use% Mounted on
    devtmpfs        485M     0  485M   0% /dev
    [root@web ~]# df -h | awk 'NR==1,NR==2 {print $1,$2}'
    Filesystem Size
    devtmpfs 485M
    [root@web ~]# df -h | awk 'NR==1,NR==2 {print $(NF-1)}'
    Mounted
    0%
     
    场景实践:查看内存当前使用状态,如果使用超过80%则发送告警邮件
    [root@shell scripts]# vim mem_use.sh
    #!/bin/bash
    #监控内存使用状态,超标时发送告警邮件
     
    Mem_Use=$(free -m|grep ^M|awk '{print $3/$2*100}')
    if [ ${Mem_Use%.*} -ge 80 ];then
           echo "内存使用率已超过80%,当前内存使用率为:$Mem_Use%" >/tmp/mem.txt
           mail -s "$(hostname -i)_$(hostname)的内存负荷过高,请注意" 276715936@qq.com </tmp/mem.txt
       else
           echo "当前内存使用率为:$Mem_Use%"
    fi
     
    4、流程控制语句if字符比较
     
    参数
    说明
    示例
    ==
    等于则条件为真
    [ "$a" == "$b" ]
    !=
    不相等则条件为真
    [ "$a" != "$b" ]
    -z
    字符串的长度为零则为真(值为空)
    [ -z "$a" ]
    -n
    字符串的长度不为空则为真(内容不为空)
    [ -n "$a" ]
    str1 > str2
    str1大于str2为真
    [ str1 > str2 ]
    str1< str2
    str1小于str2为真
    [ str1 < str2 ]
    1)单条件比对
    read -p "输入yes|no" tt
    if [ $tt == "yes" ];then
            echo  "OK"
    fi
    [root@shell scripts]# USER=root
    [root@shell scripts]# [ "$USER" = root ];echo $?
    0
    [root@shell scripts]# [ "$USER" = root1 ];echo $?
    1
    [root@shell scripts]# [ -z "$USER" ];echo $?
    1
    [root@shell scripts]# [ -z "$bbb" ];echo $?
    0
    [root@shell scripts]# [ -n "$USER" ];echo $?
    0
    [root@shell scripts]# [ -n "$bbb" ];echo $?
    1
     
    2)多整数比对条件
    [root@shell scripts]# [ 1 -lt 2 -a 5 -gt 10 ];echo $?       -a 并且  相当于&&
    1
    [root@shell scripts]# [ 1 -lt 2 -o 5 -gt 10 ];echo $?       -o 或    相当于||
    0
     
    5. 流程控制语句if正则比较
    #正则比对使用[[ ]]
    [root@shell scripts]# [[ 1 -lt 2 && 5 -gt 10 ]];echo $?
    1
    [root@shell scripts]# [[ 1 -lt 2 || 5 -gt 10 ]];echo $?
    0
     
    示例:判断一个数是整数
    [root@shell scripts]# vim zz.sh
    #!/bin/bash
    #正则判断输入的数字
    read -p "请输入一个整数:" nn
    if [[ $nn =~ ^[0-9]+$ ]];then
           echo "你输入的整数是 $nn"
    else
           echo "你输入的不是整数"
    fi
     
    6. 流程控制语句if场景示例
    场景应用:写一个创建用户的脚本,需要输入创建用户前缀,比如oldboy,以及后缀,比如123
    [root@shell scripts]# vim create_user.sh
    #!/bin/bash
    #创建用户
    read -p "请输入用户的前缀:" qz
    if [[ ! $qz =~ ^[a-Z]+$ ]];then
        echo "你输入的不是字母..."
        exit
    fi
     
    read -p "请输入用户的后缀:" hz
    if [[ $hz =~ ^[0-9]+$ ]];then
        user=${qz}${hz}
        id = $user &>/dev/null
           if [ $? -eq 0 ];then
              echo "$user用户已经存在"
              exit
           else
              useradd $user
           echo "用户已经创建成功${qz}${hz}"
           fi
    fi
     
    场景应用:使用root用户清空/var/log/messages日志,并每次执行保留最近100行
        1)判断必须是root                       字符判断
        2)判断文件必须存在                   文件判断
        3)清空需要保留最近100行          tail
    [root@shell scripts]# vim if_logs.sh
    #!/bin/bash
    #使用root用户清空/var/log/messages日志,并每次执行保留最近100行
     
    if [ $UID -eq 0 ] && [ $USER == "root" ];then
         if [ -f /var/log/messages ];then
            tail -100 /var/log/messages >/var/log/messages.bak
            cat /var/log/messages.bak > /var/log/messages
            echo "===========成功==========="
         else
            echo "文件/var/log/messages不存在"
            exit
         fi
    else
            echo "$USER没有执行此脚本的权限"
    fi
     
    场景应用:判断httpd服务是否正常启动,文件名必须是httpd_daemon.sh
          ps aux                 ps aux | grep httpd | grep -v grep
          netstat -lntp
          lsof
          systemctl
          telnet
          namp
    1)先判断服务是否是启动     #过滤inactive  active信息   
    [root@shell ~]# systemctl status httpd | awk '/^.*Active/ {print $2}'
    2)如果服务是启动在判断端口是否存在
    netstat -lntup|grep "$service"
    3)最后判断进程是否存在
    ps -aux|grep "$service"|grep -v grep|grep -v pts
     
    [root@shell scripts]# vim service_deamon.sh
    #!/bin/bash
    #判断服务是否正常启动
     
    read -p "请输入一个服务名:" service
    Status=$(systemctl status $service|awk '/^.*Active/ {print $2}')
    # 1.监测服务状态
    if [ "$Status" == "active" ];then
          sleep 1
          echo "==== $service服务监测是$Status状态"
      else
          sleep 1
          echo "==== $service服务监测是$Status状态"
    fi
    # 2.判断端口是否存在
    netstat -lntup|grep "$service" >/dev/null
    if [ $? -eq 0 ];then
          sleep 1
          echo "==== $service服务端口正常"
       else
          sleep 1
          echo "==== $service服务端口没有启动"
    fi
    # 3.判断进程是否存在
    ps -aux|grep "$service"|grep -v grep|grep -v pts >/dev/null
    if [ $? -eq 0 ];then
          sleep 1
          echo "==== $service服务进程正常"
       else
          sleep 1
          echo "==== $service服务没有进程"
    fi

    场景应用:备份MySQL中的所有数据库,每个库一个.sql的文件,排除没用的
      1)如何拿到所有的库名称
    mysql -uroot -p123456 -e "show databases;"|sed 1d|grep -Ev "*_schema|test"|sed -r 's#(.*)#mysqldump -uroot -p123456 -B 1 >/backup/1.sql#g'|bash
      2)拿到后一个一个的备份
    mysqldump -uroot -p123456 -B mysql >/backup/mysql_$(date +%F -d "-1day").sql
     
    [root@shell ~]# vim mysqldump_all.sh
    #!/bin/bash
    #备份MySQL数据库中所有数据,排除没用的
    db=$(mysql -uroot -p123456 -e "show databases;"|sed 1d|grep -Ev "*_schema|test")
    for i in $db
    do
          mysqldump -uroot -p123456 -B $i >/backup/${i}_$(date +%F -d "-1day").sql
    done
     
    7. 流程控制语句case基本概述
    case用来实现对程序流程的选择、循环、等进行控制,语法如下:
    case  变量  in 
    变量  1)
           命令序列 1;
    变量  2)
           命令序列2;
    *) 
           无匹配后命令序列、
    esac
    #!/bin/bash
    #case循环语句
     
    cat <<EOF
    ***************
    *  1. backup  *
    *  2. copy    *
    *  3. quit    *
    ***************
    EOF
    read -p "请输入你想操作的选项[1|2|3]:" re
    case $re in
         1)
            echo "backup"
            ;;
         2)
            echo "copy"
            ;;
         3)
            echo "quit"
            ;;
         *)
            echo "请注意输入"
            echo "USAGE:$0 {1|2|3}"
    esac
     
    8. 流程控制语句case场景示例
    场景应用1:写一个rsync的启动和停止的脚本
    思路:
       1)如何启动rsync --deamon
            ps -ef | grep -v grep
       2) 如何停止的命令kill
           pkill rsync

    [root@shell scripts]# vim case_rsync.sh
    #!/bin/bash
    #用case判断语句如何写rsync服务启动脚本
     
    source /etc/init.d/functions  #在当前shell环境中source functions
    rs=$1
    case $rs in
         start)   # 在启动rsync服务前,先判断是否存在pid文件(手动创建的pid文件)
            if [ ! -f /var/run/rsync.pid ];then
               #如果不存在pid,则手动创建并启动服务(加锁机制,防止服务重复启动或停止)
               touch /var/run/rsync.pid
               rsync --daemon
               action "rsync starting..." /bin/true
            else
               action "rsync service running..." /bin/false
            fi
            ;;
     
         stop)
            if [ ! -f /var/run/rsync.pid ];then
               action "rsync service stoppend..." /bin/false
            else
               #如果停止服务,一定要删除pid
               rm -f /var/run/rsync.pid
               pkill rsync
               action "rsync stopping..." /bin/true
            fi
            ;;
     
         status)
            if [ ! -f /var/run/rsync.pid ];then
               echo "rsync service status inactive..."
            else
               rsync_pid=$$
               Rsync_Status=$(ps aux|grep rsync|grep -v grep|awk '{print $2}')
               echo "rsync service status active( "$Rsync_Status" )"
               echo $$  #显示当前执行进程的pid
            fi
            ;;
     
         *)
               echo "USAGE: $0 { start | stop }"
               exit
    esac
      
    case场景应用2:写一个nginx启动脚本
    [root@shell scripts]# vim case_nginx.sh
    #!/bin/bash
    #nginx启动脚本
    source /etc/init.d/functions
    Lock=(/tmp/nginx.lock)
     
    #加锁,防止脚本重复运行,脚本执行过程中重复执行会导致系统报错
    if [ -f $Lock ];then
       echo "此脚本正在运行,请稍候运行..."
       exit
    fi
    touch $Lock
     
    rs=$1
    case $rs in
       start)
           if [ -f /var/run/nginx/nginx.pid ];then
              echo "nginx服务已经启动...."
              rm -f $Lock
              exit
           else
              /usr/local/nginx/sbin/nginx
              action "nginx 服务已经启动成功...." /bin/true
           fi
           ;;
     
       stop)
           if [ -f /var/run/nginx/nginx.pid ];then
              /usr/local/nginx/sbin/nginx -s stop
              if [ $? -eq 0 ];then
                 action "nginx 关闭成功.... " /bin/true
              else
                 action "nginx 关闭失败.... " /bin/false
              fi
           else
                 action "nginx已经关闭...[error] open() /run/nginx/nginx.pid" /bin/false
           fi
           ;;
     
       reload)
           if [ -f /var/run/nginx/nginx.pid ];then
              /usr/local/nginx/sbin/nginx -t &>/dev/null
              if [ $? -eq 0 ];then
                 /usr/local/nginx/sbin/nginx -s reload
                 if [ $? -eq 0 ];then
                    action "nginx服务重载成功...." /bin/true
                 else
                    action "nginx服务重载失败...." /bin/false
                    rm -f $Lock
                    exit     
                 fi
              else
                 /usr/local/nginx/sbin/nginx -t &>err.txt
                 nginx_conf=$(awk -F "[: ]" 'NR==1 {print $(NF-1)}' err.txt)
                 nginx_line=$(awk -F "[: ]" 'NR==1 {print $(NF)}' err.txt)   
                 read -p "$nginx_conf配置有错,在$nginx_line行,是否要进入配置修改[ yes|no ]" re
                 case $re in
                      y|yes|YES)
                           vim +${nginx_line} ${nginx_conf}
                           ;;
                      n|no|NO)
                           echo "你可以先手动修改,再见!"
                           exit
                           ;;
                      *)
                           echo "USAGE:$0 {y|n}"
                 esac
              fi
           else
                   action "nginx没有启动,无法完成重载" /bin/false
           fi
           ;;
       status)
           if [ -f /var/run/nginx/nginx.pid ];then
              nginx_pid=$(cat /var/run/nginx/nginx.pid)
              echo "nginx ( $nginx_pid ) is running"
           else
              echo "nginx is not runing"   
           fi
           ;;
     
           *)
           echo "USAGE: $0 [ start | stop | reload | status ] "           
    esac
     
    #解锁
    rm -f $Lock
     
    case场景:case实现跳板机功能
    1. 执行脚本后,需要看到所有我能管理的主机
    2. 有一个选择菜单,提示输入连接某个主机
    3. 需要写一个死循环,保证程序连接后端服务,退出后还能接着选择主机
    4. 不能让直接跳板机直接ctrl+c    ctrl+z退出,trap控制ctrl+c   ctrl+z信号
    5. 退出服务器的会话,再次登录,又可以正常操作服务器,将脚本加入 /etc/bashrc中,当用户一连接,自动执行该脚本
    [root@m01 scripts]# chmod +x jumpserver.sh
    [root@m01 scripts]# vim ~/.bashrc
    bash /server/scripts/jumpserver.sh   #如果想所有用户登录时就自动出现跳板机连接页面,就有/etc/bashrc文件加入bash /server/scripts/jumpserver.sh
    #!/bin/bash
    #case实现跳板机功能
    # 1. 执行脚本后,需要看到所有我能管理的主机
    # 2. 有一个选择菜单,提示输入连接某个主机
    # 3. 需要写一个死循环,保证程序连接后端服务,退出后还能接着选择主机
    # 4. 不能让直接跳板机直接ctrl+c    ctrl+z退出,trap控制ctrl+c   ctrl+z信号
    # 5. 退出服务器的会话,再次登录,又可以正常操作服务器,将脚本加入 /etc/bashrc中,当用户一连接,自动执行该脚本
     
    meminfo() {  #定义meminfo函数,方便后面调用,使用时要注意,调用时不用输入$,要注意与命令冲突
    cat <<-EOF
    -------------------------
    |  1) lb01 - 172.16.1.5   |
    |  2) lb02 - 172.16.1.6   |
    |  3) web01 - 172.16.1.7  |
    |  4) web02 - 172.16.1.8  |
    -------------------------
    EOF
    }
     
    meminfo  #调用meminfo函数
      trap "" HUP INT TSTP   #屏蔽输入信号,防止强制退出
     
    while true      #while死循环
    do
      read -p "请输入需要连接的主机序号:" connection
      case $connection in
         1|lb01)
            ssh root@172.16.1.5
            ;;
         2|lb02)
            ssh root@172.16.1.6
            ;;
         3|web01)
            ssh root@172.16.1.7
            ;;
         4|web02)
            ssh root@172.16.1.8
            ;;
         h)
            clear
            meminfo    #调用meminfo函数
            ;;
         exit|quit)
            exit
            ;;
         *)
           echo "USAGE: $0输入连接[ 1|2|3|4 ]"
    esac
    done
     
    case场景:实现多级菜单
    #!/bin/bash
    mem_option(){
    cat <<-EOF
    ------主菜单----
    | 1) 安装nginx   |
    | 2) 安装php     |
    | 4) 安装tomcat  |
    | 5) 退出        |
    ----------------
    EOF
    }
     
    mem_install_nginx(){
    cat <<-EOF
    --Install nginx--
    | 1) 安装nginx1.1 |
    | 2) 安装nginx1.2 |
    | 3) 安装nginx1.3 |
    | 4) 返回上一页   |
    -----------------
    EOF
    }
     
    mem_install_php(){
    cat <<-EOF
    --Install php--
    | 1) 安装php5.5 |
    | 2) 安装php5.6 |
    | 3) 安装php7.0 |
    | 4) 返回上一页 |
    ---------------
    EOF
    }
    #--------------------------------------
    mem_option
      trap "" HUP INT TSTP
    while true
    do
    read -p "请输入主菜单需要选择的选项,使用方法[1|2|3]: " option
    case $option in
       1|nginx)
            clear
            mem_install_nginx
            read -p "请输入安装nginx的版本:" nginx_install_option
            case $nginx_install_option in
               1|1.1)
                     echo "install nginx 1.1 is done"
                     ;;
               2|1.2)
                     echo "install nginx 1.2 is done"
                     ;;
               3|1.3)
                     echo "install nginx 1.3 is done"
                     ;;
               4|exit)
                     clear
                     mem_option
                     ;;
               *)
                     clear
                     echo "USAGE: [ 1|2|3|4 ]"
                     mem_install_nginx
            esac
            ;;
       2|php)
            clear
            mem_install_php
            read -p "请输入安装PHP的版本: " php_install_option
            case $php_install_option in
                 1|5.5)
                       echo "install php 5.5 is done"
                       ;;
                 2|5.6)
                       echo "install php 5.6 is done"
                       ;;
                 3|7.0)
                       echo "install php 7.0 is done"
                       ;;
                 4|exit)
                       clear
                       mem_option
                       ;;
                 *)
                       clear
                       echo "USAGE: [ 1|2|3|4 ]"
                       mem_install_php
            esac
            ;;
       3|tomcat)
                echo "----- tomcat install done ------"
                ;;
       exit)
                exit
                ;;
       *)
                echo "USAGE:[ 1|2|3 ]"
    esac
    done
     
     
  • 相关阅读:
    导入导出
    封装本地文件路径
    读书书单
    Spring源码阅读-BeanFactory体系结构分析
    Spring源码阅读-ApplicationContext体系结构分析
    Spring源码阅读-IoC容器解析
    Spring源码阅读环境搭建
    【spring实战第五版遇到的坑】第14章spring.cloud.config.uri和token配置项无效
    【spring实战第五版遇到的坑】4.2.3中LDAP内嵌服务器不启动的问题
    【spring实战第五版遇到的坑】3.2中配置关系映射时,表名和3.1中不一样
  • 原文地址:https://www.cnblogs.com/chenyun1/p/12940332.html
Copyright © 2020-2023  润新知