Shell流程语句
1. shell流程控制
流程控制是改变程序运行顺序的指令。linux shell有一套自己的流程控制语句,其中包括条件语句(if),循环语句(for,while),选择语句(case)。
2. if语句
格式:if list; then list; [ elif list; then list; ] ... [ else list; ] fi
2.1 单分支
if 条件表达式; then
命令
fi
[root@localhost ~]# vim test.sh #!/bin/bash if [ 1 -eq 1 ];then echo "yes" fi [root@localhost ~]# bash test.sh yes
2.2 双分支
if 条件表达式; then
命令
else
命令
fi
#!/bin/bash if [ 1 -eq 2 ];then echo "yes" else echo "no" fi [root@localhost ~]# bash -x test.sh #-x,调试 + '[' 1 -eq 2 ']' + echo no no
#判断crond进程是否正在运行 [root@localhost ~]# ps aux | grep "grep" root 11941 0.0 0.0 112648 956 pts/3 S+ 20:30 0:00 grep --color=auto [root@localhost ~]#vim cron_d.sh #!/bin/bash NAME=crond NUM=$(ps aux | grep $NAME | grep -vc grep) if [ $NUM -eq 1 ]; then echo "$NAME running." else echo "$NAME is not running!" fi
#检查主机是否在线 #!/bin/bash if ping -c 1 192.168.1.1 &>/dev/null; then #if可以直接对命令进行判断 echo "OK." else echo "NO!" fi
2.3 多分支
if 条件表达式; then
命令
elif 条件表达式; then
命令
else
命令
fi
#!/bin/bash N=$1 # 接收用户输入参数 if [ $N -eq 3 ]; then echo "eq 3" elif [ $N -eq 5 ]; then echo "eq 5" elif [ $N -eq 8 ]; then echo "eq 8" else echo "no" fi
如果第一个条件符合就不再向下匹配。
在写脚本时先在命令测试,无误后再写入脚本
if语句实例:编写一个计算器,实现简单的加减乘除
要求:
请输入一个数字: 7
请输入运算符:+
请输入第二个数字:7
7+7=14
[root@localhost ~]# vim count.sh #!/bin/bash read -p "请输入第一个数字:" num1 read -p "请输入运算符:" cha read -p "请输入第二个数字:" num2 count (){ echo "${num1}${cha}${num2}=$((${num1}${cha}${num2}))" } error () { echo "Usage:$0 {+|-|*|/|0-9}" } if [ -n '$num1' -a -n '$hca' -a -n '$num2' ];then if [ "$cha" == "+" ];then count elif [ "$cha" == "-" ];then count elif [ "$cha" == "*" ];then count elif [ "$cha" == "/" ];then count else error fi else echo '输入内容不能为空' fi :wq [root@localhost ~]# bash count.sh 请输入第一个数字:8 请输入运算符:+ 请输入第二个数字:2 8+2=10 [root@localhost ~]# bash count.sh 请输入第一个数字:8 请输入运算符:* 请输入第二个数字:10 8*10=80 [root@localhost ~]# bash count.sh 请输入第一个数字:l 请输入运算符:l 请输入第二个数字:l Usage:count.sh {+|-|*|/|0-9}
3. for 语句
用于批量化部署
格式:for name [ [ in [ word ... ] ] ; ] do list ; done
for 变量名 in 取值列表; do
命令
done
或者
for 变量名 in 取值列表
do
命令
done
[root@localhost ~]# vim for_test.sh #!/bin/bash for i in {1..5} do echo $i sleep 1 #沉睡1秒,即1秒打印一个 done :wq [root@localhost ~]# bash for_test.sh 1 2 3 4 5
#实现100以内的偶数/奇数和
[root@localhost ~]#vim count_ou.sh #!/bin/bash sum=0 for i in `seq 0 2 100` #偶数和 do let sum+=$i done echo $sum :wq [root@localhost ~]# bash count_ou.sh 2550 [root@localhost ~]# vim count_ji.sh #!/bin/bash sum=0 for i in `seq 1 2 100` #奇数和 do let sum+=$i done echo $sum :wq [root@localhost ~]# bash count_ji.sh 2500
#批量检查当前教室192.168.16.(1-10)网段主机是否在线 [root@localhost ~]# vim check_ip.sh #!/bin/bash . /etc/init.d/functions #引用文件 ip=192.168.16. for i in {1..10} do if ping -c 1 -w 1 $ip$i &>/dev/null;then #返回执行结果0或1,其他文件导入黑洞文件 echo -n "$ip$i" #-n,不换行 success #相应function函数 echo "" #输出空格 else echo -n "$ip$i" failure echo “ ” fi done [root@localhost ~]# bash check_ip.sh 192.168.16.1 [ OK ] 192.168.16.2 [ OK ] 192.168.16.3 [FAILED] 192.168.16.4 [FAILED] 192.168.16.5 [FAILED] 192.168.16.6 [FAILED] 192.168.16.7 [FAILED] 192.168.16.8 [FAILED] 192.168.16.9 [FAILED] 192.168.16.10 [FAILED]
4. while语句用于监控
条件为真就进入死循环;条件为假就退出循环
格式:while list; do list; done
while 条件表达式; do
命令
done
[root@localhost ~]# vim while_.sh #!/bin/bash n=0 while [ $n -lt 5 ] do echo "$n" let n++ done :wq [root@localhost ~]# bash while_.sh 0 1 2 3 4
当条件表达式为 false 时,终止循环。
条件表达式为 true,将会产生死循环。
死循环有什么作用那?
可以用来后台运行检测脚本,如下是是一个检测脑裂的脚本
我们只需要在命令行中输入 nohup bash naolie.sh & 即可在后台持续运行该脚本
#检测终端数量 [root@localhost ~]# vim check_zh.sh= #!/bin/bash while true do num=`who | wc -l` echo"当前终端数量为$num" sleep 1 done :wq [root@localhost ~]# bash check_zh.sh 当前终端数量为5 当前终端数量为5 当前终端数量为6 当前终端数量为6 ^C
#关掉该终端后停止检测 #将检测文件写入文件并放在后台执行 [root@localhost ~]# vim check_zh.sh #!/bin/bash while true do num=`who | wc -l` echo "当前终端数量为$num" >> /root/check_zh sleep 1 done :wq [root@localhost ~]# bash check_zh.sh & #&表示放在后台 [1] 12336 [root@localhost ~]# tail -f check_zh 当前终端数量为3 当前终端数量为3 …..
#关闭写入检测文件的该终端,监测终端停止 #若想关闭终端继续检测,将该监测文件挂起 [root@localhost ~]# nohup bash check_zh.sh & [1] 16949 [root@localhost ~]# nohup: ignoring input and appending output to ‘nohup.out’[root@localhost ~]# ls nohup.out #生成nohup.out文件 在监测则在该终端关闭后无影响 [root@localhost ~]# tail -f check_zh 当前终端数量为3 当前终端数量为3 当前终端数量为2 当前终端数量为2 …….
#若要关掉该监测2关掉运行的进程即可 [root@localhost ~]# ps aux | grep check_zh root 13519 0.0 0.1 113124 1448 ? S 22:19 0:00 bash check_zh.sh root 16949 0.0 0.1 113124 1432 pts/0 S 22:28 0:00 bash check_zh.sh root 18476 0.0 0.0 112648 960 pts/0 R+ 22:31 0:00 grep --color=auto check_zh [root@localhost ~]# kill -9 13519 [root@localhost ~]# kill -9 16949
#逐行读取passwd文件 [root@localhost ~]# vim read.sh #!/bin/bash cat /etc/passwd | while read line do echo "$line" sleep 1 done :wq [root@localhost ~]# bash read.sh root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin
5. break和continue语句
break 是终止循环。
continue 是跳出当前循环。
[root@localhost ~]# vim test_break.sh #!/bin/bash sum=0 while true do if [ $sum -eq 5 ];then break fi let sum++ echo "$sum" done :wq [root@localhost ~]# bash test_break.sh 1 2 3 4 5
[root@localhost ~]# vim test_continue.sh #!/bin/bash sum=0 while true do let sum++ if [ $sum -eq 5 ];then continue fi echo "$sum" sleep 1 done :wq [root@localhost ~]# bash test_continue.sh 1 2 3 4 #跳过了5,仅跳出来此次循环 6 7 8 ^C
6. case语句(sentos6常用)
case 语句一般用于选择性来执行对应部分块命令。
case 模式名 in
模式 1)
命令
;;
模式 2)
命令
;;
*)
不符合以上模式执行的命令
esac
每个模式必须以右括号结束,命令结尾以双分号结束,最后一个模式不需要添加;;。
[root@localhost ~]# vim test_case.sh #!/bin/bash case $1 in [0-9]) echo "数字" ;; [a-z]) echo "a-z" ;; [A-Z]) a=`tr $1 a-z` #大写转化成小写 echo "$a" ;; *) echo "结束" esac :wq [root@localhost ~]# bash test_case.sh 1 数字 [root@localhost ~]# bash test_case.sh a a-z [root@localhost ~]# bash test_case.sh A a-z
#内存不足报警
#查看内存 [root@localhost ~]# free total used free shared buff/cache available Mem: 999936 119616 613732 6856 266588 698092 Swap: 0 0 0 [root@localhost ~]# free -h total used free shared buff/cache available Mem: 976M 116M 599M 6.7M 260M 681M Swap: 0B 0B 0B [root@localhost ~]# free -h | grep M Mem: 976M 116M 599M 6.7M 260M 681M [root@localhost ~]# free -h | grep M | cut -d'M' -f4 599 [root@localhost ~]# free -h | grep M | cut -d'M' -f4 | tr -d ' ' 598 [root@localhost ~]# vim mem_warning.sh #!/bin/bash while true do mem=`free -h | grep M | cut -d'M' -f4 | tr -d ' '` if [ $mem -lt 500 ];then echo '当前内存不足,请及时处理' break #警告一次即可 fi done :wq
7. 实训
1> 写一个脚本: 实现自动化一键部署NFS服务器端和客户端
#服务端:192.168.16.5;客户端:192.168.16.6 .5: [root@localhost ~]# vim nfs_auto_client.sh #!/bin/bash mount /dev/cdrom /mnt &>/dev/null yum install rpcbind nfs-utils -y &>/dev/null mkdir /zxj &>/dev/null mount -t nfs 192.168.16.6:/zxj /zxj df -h
[root@localhost ~]# vim nfs_auto_server.sh #!/bin/bash #desc: This shell is for auto deploy nfs #date: 2019-05-04 #author: zxj #服务端配置 pack_num=`ls /mnt | wc -l` if [ $pack_num -eq 0 ];then mount /dev/cdrom /mnt &>/dev/null #检测是否挂载 fi yum install rpcbind nfs-utils -y &>/dev/null if [ $? -ne 0 ];then exit fi mkdir /zxj &>/dev/null chown -R nsfnabody: /zxj echo "/zxj 192.168.16.6(rw)" > /etc/exports systemctl restart rpcbind nfs &>/dev/null #客户端配置 scp ./nfs_auto_client.sh 192.168.16.5:/root ssh 192.168.16.6 bash /root/nfs_auto_client.sh [root@localhost ~]# bash nfs_auto_server.sh
2> 第二个脚本:实现批量化检测当前教室主机在线状况,在线主机保存至一个文件中
[root@localhost ~]# vim check_online.sh #!/bin/bash touch online echo "在线ip:" > online ip=192.168.16. for i in {5..20} do if ping -c 1 -w 1 $ip$i &>/dev/null;then echo "$ip$i在线" echo "$ip$i" >> online else echo "$ip$i不在线" fi done cat online :wq [root@localhost ~]# bash check_online.sh 192.168.16.5在线 192.168.16.6在线 192.168.16.7不在线 192.168.16.8不在线 192.168.16.9不在线 192.168.16.10不在线 192.168.16.11不在线 192.168.16.12不在线 192.168.16.13不在线 192.168.16.14不在线 192.168.16.15不在线 192.168.16.16在线 192.168.16.17不在线 192.168.16.18不在线 192.168.16.19不在线 192.168.16.20不在线 在线ip: 192.168.16.5 192.168.16.6 192.168.16.16 #或者 [root@localhost ~]# vim check_online.sh #!/bin/bash touch online echo "在线ip:" > online ip=192.168.16. . /etc/init.d/functions for i in {5..20} do if ping -c 1 -w 1 $ip$i &>/dev/null;then echo -n "$ip$i" success echo "" echo "$ip$i" >> online else echo -n "$ip$i" failure echo "" fi done cat online [root@localhost ~]# bash check_online.sh 192.168.16.5 [ OK ] 192.168.16.6 [ OK ] 192.168.16.7 [FAILED] 192.168.16.8 [FAILED] 192.168.16.9 [FAILED] 192.168.16.10 [FAILED] 192.168.16.11 [FAILED] 192.168.16.12 [FAILED] 192.168.16.13 [FAILED] 192.168.16.14 [FAILED] 192.168.16.15 [FAILED] 192.168.16.16 [ OK ] 192.168.16.17 [FAILED] 192.168.16.18 [FAILED] 192.168.16.19 [FAILED] 192.168.16.20 [FAILED] 在线ip: 192.168.16.5 192.168.16.6 192.168.16.16
3> 第三个脚本:实现批量化创建100个用户,并创建8位随机密码,且可登陆
#!/bin/bash for i in {1..100} do useradd user$i passwd=`echo $RANDOM | md5sum | cut -c 1-8` echo $passwd | passwd --stdin user$i echo -e "账户:user$ \n密码:$passwd" done
4> 第四个脚本:找出系统中含有某个关键词的文件,并输出到终端,关键词用户输入指定
[root@localhost ~]# vim find_key.sh #!/bin/bash read -p "Please input your keyword:" key for file in `find / -type f`` do if grep "$key" $file &>/dev/null;then echo "$file" fi done :wq [root@localhost ~]# bash find_key.sh Please input your keyword:anaconda /boot/grub2/device.map ……
5> 第五个脚本:批量判断当前目录下所有文件类型
[root@localhost ~]# vim type.sh #!/bin/bash for file in `ls /root` do type=`ls -ld $file | cut -c 1` if [ "$type" == "-" ];then echo "$type------->$file=====普通文件" elif [ "$type" == "d" ];then echo "$type------->$file=====目录文件" elif [ "$type" == "l" ];then echo "$type------->$file=====链接文件" else echo "$type------->$file=====未知文件" fi done :wq [root@localhost ~]# bash type.sh -------->anaconda-ks.cfg=====普通文件 -------->find_key.sh=====普通文件 -------->type.sh=====普通文件
6> 找到以.sh结尾的文件,计算文件大小总和,以KB为单位
#方法一: 用cut分割 [root@localhost ~]# vim sum_sh.sh #!/bin/bash sum=0 for file in `find / -name "*.sh"` do size=`ls -l $file | cut -d " " -f 5` let sum+=$size done echo "$(($sum/1024))KB" [root@localhost ~]# bash sum_sh.sh 623KB # 方法二:用awk分割 [root@localhost ~]# vim sum_sh1.sh #!/bin/bash sum=0 for file in `find / -name "*.sh"` do size=`ls -l $file | awk -F " +" '{printf $5}'` let sum+=$size done echo "$(($sum/1024))KB" :wq [root@localhost ~]# bash sum_sh1.sh 623KB