02-shell的流程控制
流程控制语句内容介绍
-
1. 流程控制语句if基本概述
-
2. 流程控制语句if文件比较
-
3. 流程控制语句if整数比较
-
4. 流程控制语句if字符比较
-
5. 流程控制语句if正则比较
-
6. 流程控制语句if场景示例
-
7. 流程控制语句case基本概述
-
8. 流程控制语句case场景示例
-
9. 交互式脚本expect场景示例
1、流程控制语句if基本概述
-
单分支结构
if [];then
echo ""
fi
-
双分支结构
if grep "$1" /etc/passwd >/dev/null;then
echo "ok"
else
echo "error"
fi
-
多分支结构
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实现跳板机功能
-
执行脚本后,需要看到所有我能管理的主机
-
有一个选择菜单,提示输入连接某个主机
-
需要写一个死循环,保证程序连接后端服务,退出后还能接着选择主机
-
不能让直接跳板机直接ctrl+c ctrl+z退出,trap控制ctrl+c ctrl+z信号
-
退出服务器的会话,再次登录,又可以正常操作服务器,将脚本加入 /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