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
 
 
posted @ 2020-05-22 23:09  向云而生(陈云)  阅读(234)  评论(0编辑  收藏  举报