您的位置:首页 > 运维架构 > Shell

shell脚本-循环、case语句,函数及中断控制

2019-04-10 00:09 881 查看

简介

循环

  1. for循环

在Shell脚本应用中,常见的for循环采用遍历式、列表式的执行流程,通过指定变量从值列表中循环赋值,每次复制后执行固定的一组操作。

  • 语法结构
for  变量名  in  值列表			#可以是数值、字母,以空格隔开
do
命令序列
done
for  变量名  in  {1..5}			#{起始值~末尾值}==>1 2 3 4 5
do
命令序列
done
for  变量名  in  `seq 5`			#用于以指定增量从首数开始打印数字到尾数,即产生从某个数到另外一个数之间的所有整数
do
命令序列
done
for  变量名  in  `ls /etc/*.conf`			#读取文件内容
do
命令序列
done
  • 例子1 利用循环打印出reve
#A:
#!/bin/bash
#循环打印出reve
a=10
for i in 1 2 3
do
echo "reve"
done
-----------------------------------------------
[root@reve shell]# bash test.sh			#A: 结果
reve
reve
reve

#B:
#!/bin/bash
#循环打印出reve
a=10
for i in {1..3}
do
echo "reve"
done
-----------------------------------------------
[root@reve shell]# bash test.sh		#B: 结果
reve
reve
reve
------------------------------------------------
#C:
#!/bin/bash
#循环打印出reve
a=10
for i in `seq $a`	#seq命令用于以指定增量从首数开始打印数字到尾数,即产生从某个数到另外一个数之间的所有整数,并且可以对整数的格式、宽度、分割符号进行控制,
#在这里的 `seq $a` 表示:1 2 3 4 5
do
echo "reve"
done
[root@reve shell]# bash test.sh			#C: 结果
reve
reve
reve
reve
reve
reve
reve
reve
reve
reve
---------------------------------------------
  • C语言风格的for循环格式 通过变量控制,条件成立循环
  • 步长可以控制
for((初值;条件;步长控制))
do
命令序列
done
  • 例子2利用循环ping 一个网段,有多少台主机可以ping通

注意ping命令可以测试某台主机的连通性,
使用-c选项可以设置ping的次数,
使用-i选项可以设置多次ping之间的间隔时间(单位秒),
使用-W选项可以设置ping不通时的超时时间(单位秒)。

#!/bin/bash
#利用循环ping 一个网段,有多少台主机可以ping通
for i in {40..50}			#由于我的主机的IP是49,所以我就缩小范围,节省时间。
do
ping -c 3 -i 0.2 -W 1 192.168.4.$i &> /dev/null		#输出结果给丢弃掉
if [ $? -eq 0 ];then		#判断上一条语句的是否ping通,通就说明,执行成功,#? 返回 0.反之$? 返回 1
echo " 192.168.4.$i 通了"
let a++		#通了,就子增 + 1
else
echo " 192.168.4.$i 不通"
let b++		#不通也自增 + 1
fi
done

echo "有$a 台主机通了"		#统计最后的结果
echo "有$b 台主机不通"
---------------------------------------------------
[root@reve shell]# vim Ping_color.sh
[root@reve shell]# bash Ping_color.sh
192.168.4.45 不通
192.168.4.46 不通
192.168.4.47 不通
192.168.4.48 不通
192.168.4.49 通了
192.168.4.50 不通
有1 台主机通了
有5 台主机不通
[root@reve shell]# vim Ping_color.sh
[root@reve shell]# bash Ping_color.sh
192.168.4.45 不通
192.168.4.46 不通
192.168.4.47 不通
192.168.4.48 不通
192.168.4.49 通了
192.168.4.50 不通
有1 台主机通了
有5 台主机不通
  • 例子3一次性创建10个账户
#!/bin/bash
#一次性创建10个账户
for i in {1..10}
do
useradd  user$i
done
----------------------------
[root@reve shell]# bash Create_user.sh			#创建用户成功,是不会有提示信息的
[root@reve shell]# bash Create_user.sh
useradd:用户“user1”已存在
useradd:用户“user2”已存在
useradd:用户“user3”已存在
useradd:用户“user4”已存在
useradd:用户“user5”已存在
useradd:用户“user6”已存在
useradd:用户“user7”已存在
useradd:用户“user8”已存在
useradd:用户“user9”已存在
useradd:用户“user10”已存在
#但是这个脚本存在一些问题,用户名写死了,不符合实际情况
-----------------------------
#我们可以让for循环读取文件的内容,例如读取员工信息表。按照里面的名字来创建名字
[root@reve shell]# cat /root/user 		#创建这份文件,文件内容是用户名
zhangsan
lisi
wangwu
reve
dingren

#!/bin/bash
#读取文件中的用户名,创建用户
for i in `cat /root/user`		#让for循环读取这份文件
do
useradd  $i
done
---------------------------------------
[root@reve shell]# bash Create_user.sh
[root@reve shell]# bash Create_user.sh
useradd:用户“zhangsan”已存在
useradd:用户“lisi”已存在
useradd:用户“wangwu”已存在
useradd:用户“reve”已存在
useradd:用户“dingren”已存在
[root@reve shell]# vim Create_user.sh
  1. while 循环

while循环属于条件式的执行流程,会反复判断指定的测试条件,只要条件成立即执行固定的一组操作,直到条件变化为不成立为止。所以while循环的条件一般通过变量来进行控制,在循环体内对变量值做相应改变,以便在适当的时候退出,避免陷入死循环。

  • 语法结构
while  条件测试		#没有冒号 “ : ” 但是有空格
do
命令序列
done
while :				#有空格
do
命令序列
done
  • while死循环:
#!/bin/bash
whlie :		#条件永远成立 ==死循环
do
echo "abc"
done
执行这样的脚本和会让机器陷入死循环,会消耗大量的CPU资源,如下图片。
我用一台虚拟机执行这样程序,这里可以看到我的一个CPU资源已经达到了100%。这样长期执行这样的脚本,会对机器造成很大影响。所以我们在执行while循环,需注意避免进入这样的死循环。

  • 例子4利用while循环猜一个随机生成的数字
#!/bin/bash
#利用while循环猜一个数字
Num=$[RANDOM% 100 + 1]		#随即生成一个数,这个值不参与while循环当中。
b=0
while :
do
let b++									#需要提前对b进行初始化复为0
read -p "请输入一个数字(1~100):" a		#从键盘上读取一个值
if [ $a -eq $Num ];then
echo "你猜对了,总计:猜了$b次"
exit 2							#猜对了就退出,避免进入死循环
elif [ $a -gt $Num ];then
echo "你猜大了"
else
echo "你猜小了"
fi
done
  • 例子5 检测某一网段,列出不在线的主机地址
#!/bin/bash
i=1
while [ $i -le 254 ]		# <= 254
do
IP="192.168.4.$i"
ping -c 3 -i 0.2 -W 1 $IP &> /dev/null
if [ $? -eq 0 ] ; then
echo "Host $IP is up."
else
echo "Host $IP is down."
fi
let i++
done

分支

Case语句case分支节结构语法结构执行流程Demo
  1. case分支:与if类似,可以说是if的简化版本

case分支属于匹配执行的方式,它针对指定的变量预先设置一个可能的取值,判断该变量的实际取值是否与预设的某一个值相匹配,如果匹配上了,就执行相应的一组操作,如果没有任何值能够匹配,就执行预先设置的默认操作。

  • 语法结构:
case  变量  in
模式1)				#同时模式1)后面有个“)”
命令序列1 ;;		#需要注意:格式必须是两个分号
模式2)
命令序列2 ;;
.. ..
*)					# * 表示默认匹配
默认命令序列
esac
  • 例子6 完成一个简化命令的脚本,如:touch : t;
#!/bin/bash
#测试case
case $1 in		#位置变量$1和下面的字符进行匹配,并执行对应的序列
t)
touch $2 ;;		# $2 输入我们创建的文件名
v)
touch $2 ;;
c)
touch $2 ;;
*)
echo "t|v|c"
esac
---------------------------------------
#拓展:我们可以利用管道 | 来实现区分大小写的功能。或者误操作情况。可以自定义:
case $1 in		#位置变量$1和下面的字符进行匹配,并执行对应的序列
t|T|tt)
touch $2 ;;		# $2 输入我们要
v)
touch $2 ;;
c|C)					#匹配大写C和小写C都可以执行下面的命令序列
touch $2 ;;

*)
echo "t|v|c"
esac
------------------------------
#测试结果
[root@reve shell]# bash case_test.sh t /opt/case_test
[root@reve shell]# bash case_test.sh t /opt/case_test

函数

什么是函数:
- 在shell环境中,将一些需要重复性的操作,定义为公共的语句块,即可称为函数
使用函数的好处
- 使脚本代码更加简洁,增强易读性
- 提高shell脚本的执行效率
服务脚本中的函数应用
-适用与比较复杂的启动/终止控制哦操作
-方便在需要时多次调用

  • 函数定义的格式:
#格式1:
function  函数名 {
命令序列
.. ..
}
---------------------------------
格式2:类似C语言风格
函数名() {
命令序列
.. ..
}
  • 那我们来写一个函数来试试吧
[root@reve shell]# A(){
> mkdir bbbb
> touch aaaa.txt
> }
[root@reve shell]# type A			#type(用来显示指定命令的类型) 可以查看A是否为函数
A 是函数
A ()
{
mkdir bbbb;
touch aaaa.txt
}
[root@reve shell]# type B
-bash: type: B: 未找到
[root@reve shell]# A
[root@reve shell]# ls
bbbb   aaaa.txt
[root@reve shell]#
#注意:我们一般写函数,不写在终端,一般写在shell脚本当中。
  • 修改字体颜色:
[root@reve shell]# echo -e "\033[033mABC\033[0m"		#修改字体颜色
ABC	#橙色
[root@reve shell]# echo -e "\033[024mABC\033[0m"
ABC	#蓝色
#注意!!!:echo -e(必须带-e); \033[ :是固定格式。
# !!修改字体颜色后,的还原初始化颜色转态,以免造成麻烦。
# !!\033[0m : 还原初始化颜色
  • 举例7 书写一个能够修改字体颜色的函数
#!/bin/bash
#一个修改字体颜色的函数
Change_color(){
echo -e "\033[$1m$2\033[0m"
}
Change_color 31 REVE
Change_color 32 REVE
Change_color 33 REVE
Change_color 34 REVE
Change_color 35 REVE
Change_color 36 REVE
Change_color 37 REVE
Change_color 38 REVE
-------------------------------------
#结果
[root@reve shell]# vim Change_color.sh
[root@reve shell]# bash Change_color.sh
REVE	#红色
REVE	#绿色
REVE	#橙色
REVE	#蓝色
REVE	#粉色
REVE	#浅蓝色
REVE	#灰色
REVE	#黑色
[root@reve shell]#
  • 拓展测试某一个网段的IP地址,通了显示绿色,不同显示红色

我们可以利用我们刚才的代码,来实现

[root@reve shell]# vim Ping_color.sh
#!/bin/bash
#利用循环ping 一个网段,有多少台主机可以ping通

Change_color(){
echo -e "\033[$1m$2\033[0m"
}

for i in {45..50}                       #由于我的主机的IP是49,所以我就缩小范围,节省时间。
do
ping -c 3 -i 0.2 -W 1 192.168.4.$i &> /dev/null         #输出结果给丢弃掉
if [ $? -eq 0 ];then            #判断上一条语句的是否ping通,通就说明,执行成功,#? 返回 0.反之$? 返回 1问题
Change_color 32 " 192.168.4.$i 通了"
let a++         #通了,就子增 + 1
else
Change_color 31 " 192.168.4.$i 不通"
let b++         #不通也自增 + 1
fi
done

echo "有$a 台主机通了"          #统计最后的结果
echo "有$b 台主机不通"

测试结果

[root@reve shell]# bash Ping_color.sh
192.168.4.45 不通	#红色
192.168.4.46 不通	#红色
192.168.4.47 不通	#红色
192.168.4.48 不通	#红色
192.168.4.49 通了	#绿色
192.168.4.50 不通	#绿色
有1 台主机通了
有5 台主机不通
  • shell版本fork炸弹 仅13个字符:.(){.|.&};.
  • 递归死循环,可迅速耗尽系统资源
.(){		#定义一个名为 . 的函数
.|.&		#在后台递归调用函数
}
.			#再次调用函数

#注意:此操作非常危险,尽量在虚拟上使用。
#执行此脚本后,可以通过强制关机重启,即可恢复

中断退出

通过break、continue、exit在Shell脚本中实现中断与退出的功能。

类型 作用
break(中断) 可以结束整个循环
continue(继续) 结束本次循环,进入下一次循环
exit (退出) 结束整个脚本
  • 例子8:测试这三个中断的效果
#continue
#!/bin/bash
for i in {1..6}
do
[$i -eq 4 ] && continue         #当循环到4的时候,退出本次循环,继续下次循环
echo $i
done
echo hahaha
--------------------------
#效果
[root@reve shell]# bash Test_contiune.sh
1
2
3
5
6
hahaha
-------------------------------
#break
#!/bin/bash
for i in {1..6}
do
[$i -eq 4 ] && break         #当循环到4的时候,退出本次循环
echo $i
done
echo hahaha
--------------------------
#效果
[root@reve shell]# bash Test_contiune.sh
1
2
3
hahaha
[root@reve shell]#
---------------------------
#exit
#!/bin/bash
for i in {1..6}
do
[$i -eq 4 ] && exit         #当循环到4的时候,退出程序
echo $i
done
echo hahaha
--------------------------
[root@reve shell]# bash Test_contiune.sh
1
2
3
[root@reve shell]#
  • 例子9:把用户每次输入的值进行求和,输入0则结束
#!/bin/bash
#把用户输入的值进行求和,输入0则结束
sum=0
while :			#利用while进行循环
do
read -p "请输入一组合数字,0结束" Num
[ $Num  -eq 0 ] && break		#把0作为判断条件
sum=$[Num + sum]
done
echo $sum
----------------------
#结果
[root@reve shell]# bash While_sum.sh
请输入一组合数字,0结束5
请输入一组合数字,0结束5
请输入一组合数字,0结束5
请输入一组合数字,0结束5
请输入一组合数字,0结束0
20
  • 例子10:找出1~20以内6的倍数,并输出她的平方值
#!/bin/bash
#找出1~20以内6的倍数,并输出她的平方值
sum=0
Num=0
for i in {1..20}
do
Num=$[i % 6]
if [ $Num -eq 0 ];then
sum=$[i*i]
echo "6的倍数平方值为 $sum "
fi
done
----------------------
#结果
[root@reve shell]# bash six_sqrt.sh
6的倍数平方值为 36
6的倍数平方值为 144
6的倍数平方值为 324

总结

小结
循环
for循环,语法格式、C语言风格、长度控制
while循环、语法格式,死循环问题、
case 分支
语法结构、管道的用法(大小写的匹配: T|t|tt)、
函数
函数定义、函数使用、shell的炸弹、
中断
中断类型:contine、exit、break,作用和区别
补充
修改字体颜色,大小写匹配
  • 常见问题
#for 故障错误信息
#基本语法错误,
#for循环的执行,需要嵌入到do和doe中间
#使用case语句时,需要记住后面是以 ;; 结尾的

写的不好,请大家见谅哈

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: