Shell编程之循环语句与函数


前言

在实际工作中,经常会遇到某项任务需要多次执行的情况,而每次执行时仅仅是处理的 对象不一样,其他命令相同。例如,根据通讯录中的姓名列表创建系统账号,根据服务器清 单检查各主机的存活状态,根据 IP 地址黑名单设置拒绝访问的防火墙策略等。
当面对各种列表重复任务时,使用简单的 if 语句已经难以满足要求,而顺序编写全部代码更是显得异常烦琐、困难重重。而在不同场景使用不同的循环语句,可以很好地解决类似的问题。


一、for循环语句

1.for语句的结构

  • 读取不同的变量值,用来逐个执行同一组命令
#格式:
for 变量名 in 取值列表
do
	命令序列
done

在这里插入图片描述

1. 例:

[root@c7-1 ~]# vim for.sh
#!/bin/bash
for i in {a..d}			//变量i={abcd}
do						//命令序列
        echo $i 		//输出abcd
done					//结束循环

[root@c7-1 ~]# bash for.sh 		//运行脚本
a
b
c
d




[root@c7-1 ~]# vim for1.sh
#!/bin/bash
a=10						//定义变量
for i in `seq $a`			//变量i=取值 1~$a
do							//命令序列
        echo $i hello word 		//输出 
done						//结束循环

[root@c7-1 ~]# bash for1.sh 
1 hello word
2 hello word
3 hello word
4 hello word
5 hello word
6 hello word
7 hello word
8 hello word
9 hello word
10 hello word

[root@c7-1 ~]# vim ip.sh 

#!/bin/bash

for i in {1..255}				//定义变量,取值1~255
do								//命令序列
        ping -c 2 -i 0.1 -W 1 192.168.3.$i &>/dev/null		//ping 192.168.3.1 ~ 255 两次,0.1s,1s超时,并输入给黑洞
        if [ $? -eq 0 ]			//判断上一个命令是否正常
        then					//条件成立
                echo "192.168.3.$i Host $IP is up"
        else					//以上不成立
                echo " 192.168.3.$i Host is down"
        fi						//结束判断

done							//结束循环

################################################################

[root@c7-1 ~]# vim pass.sh

#!/bin/bash
for i in {1..5}					//定义变量i,取值1~5
do								//命令序列
        useradd dsj$i			//创建dsj 1~5
        echo "12345" | passwd --stdin dsj$i	//并设置密码
done							//循环结束
[root@c7-1 ~]# bash pass.sh 
更改用户 dsj1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 dsj2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 dsj3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 dsj4 的密码 。
passwd:所有的身份验证令牌已经成功更新。
更改用户 dsj5 的密码 。
passwd:所有的身份验证令牌已经成功更新。

[root@c7-1 ~]# vim 99.sh

#!/bin/bash
for ((i=1;i<=9;i++))			//外循环,$i的取值为1,每次循环+1,等于9结束
do
        for ((j=1;j<=i;j++))	//内循环,$j的取值为1,每次循环+1,等于$i结束
        do	
                echo -n " $i x $j=$(expr $i \* $j)"		//每次循环不换行输出 $ix$j
                        if [$j -eq $i ]					//判断$j和$i是否相等
                        then							//条件成立
                                echo -e "\n"			//则换行
                        fi								//判断结束
        done					//内循环结束
done							//外循环结束

二、while循环语句

1.while语句结构

  • 重复测试某个条件,只要条件成立则反复执行
#格式:
while 条件测试操作
do
	命令序列
done

在这里插入图片描述

2.例:

2.1

[root@c7-1 home]# vim while1.sh
#!/bin/bash
i=1						//定义变量i=1
while [ $i -le 5 ]		//当i等于5时停止循环
do

        echo $i			//每次循环输出i的值
        let i++			//每次循环+1

done					//结束循环
echo "最后i的值为:$i"	//输出最后$i的值

[root@c7-1 home]# bash while1.sh 
1
2
3
4
5
最后i的值为:6
[root@c7-1 home]# vim while2.sh 

#!/bin/bash
i=1						//定义变量i=1
while [ $i -le 100 ]	//重复测试$1是否小于等于100,直至$i等于100
        do				//命令列表
        if [[ $i%3 -ne 0 ]]	//条件检测 $i取余3,是否不等于0
        then				//条件成立
                echo "$i"	//输出 $i的值
        fi					//结束判断
        let i++				//每次循环i+1
done						//结束循环
  • 监控httpd服务状态,如果不在启动则提示报错信息
[root@c7-1 home]# vim while3.sh 

#1/bin/bash
while ps aux | grep httpd | grep -v grep &>/dev/null		//条件检测,查找有没有httpd服务,并输入给黑洞
do
        echo "httpd true"									//如果有则打印httpd true
        sleep 60											//间隔60s
done														//结束循环
DATE=`date +%T`												//定义变量
echo "服务状态异常"
echo " $DATE httpd flase服务器不在启动,请尽快处理故障  " > /home/httpd.txt	//打印什么时间服务报错,并输出给http.txt

[root@c7-1 home]# bash while3.sh 
服务状态异常
[root@c7-1 home]# cat /home/httpd.txt 
 18:47:53 httpd flase服务器不在启动,请尽快处理故障
  • 猜数字,猜不对一直猜
[root@c7-1 home]# vim  while4.sh 

#!/in/bash
NUM=8
while true 							//条件检测,true为真
do
        read -p "请输入数字:" shu	//定义交互式变量
        if [ $shu -eq $NUM ]		//条件判断,$shu 是否等于$NUM 8
        then						//条件成立则
                echo "恭喜你个大聪明猜对了"	//打印
                break						//跳出循环
        elif [ $shu -gt $NUM ]				//条件判断2,$shu是否大于$NUM
        then								//条件成立
                echo "你猜大了,求你了,猜准点吧"	//打印
        elif [ $shu -le $NUM ]				//条件判断3,$shu是否小于$NUM
        then								//条件成立
                echo "你猜小了,你咋这么笨呢"	//打印
        fi									//判断结束

done		//循环结束
#测试
[root@c7-1 home]# bash while4.sh 
请输入数字:2
你猜小了,你咋这么笨呢
请输入数字:9
你猜大了,求你了,猜准点吧
请输入数字:8
恭喜你个大聪明猜对了

  • 猜商品价格
[root@c7-1 home]# vim  while5.sh 

#!/bin/bash
PRICE=`expr $RANDOM % 1000`					//定义变量,运算一个随机数并取余
a=0											//定义变量a=0
echo "商品实际价格范围0~999,猜猜看是多少"		//打印
while true									//条件检测,true为真
do											//命令序列
        read -p "请输入你猜测的价格是多少:" n	//定义交互式变量
        let a++								//每次循环a+1
        if [ $n -eq $PRICE ]				//条件检测 $n是否等于随机数
        then								//条件成立则	
                echo "恭喜你个大聪明猜对了,实际价格是$PRICE"  //打印
                echo "你总共猜了$a次"							//打印总共猜了$a次
                break						//终止循环,并退出
        elif [ $n -gt $PRICE ]				//条件测试 $n 是否大于 随机数
        then								//条件成立
                echo "你猜高了"				//打印
        elif [ $n -lt $PRICE ]				//条件测试 $n 是否小于随机数
        then								//条件成立则
                echo "你猜低了"
        fi					//结束判断
done	//结束循环

三、until语句

1.until语句的结构

  • 重复测试某个条件,只要条件不成立则反复执行
until 条件测试操作
do
	命令序列
done

在这里插入图片描述

2.例:

[root@c7-1 home]# vim 50.sh 

#!/bin/bash
i=1				//定义变量i=1
sum=0			
until [ $i -eq 51 ]		//$i等于51时停止执行
do	
        sum=$[$i+$sum]	//定义sum等于$i + $sum
        let i++			//每次循环i+1	

done
echo "$sum				//打印结果 $sum
[root@c7-1 home]# bash 50.sh 
1275

四、函数

  • 将命令序列按格式写在一起
  • 可方便重复使用命令序列
  • shell函数定义 (两种方式):
#格式一:
[ function ] 函数名(){
	命令序列
	[return x]  //使用return或exit可以显示地结束函数
}

#格式二:
函数名 (){	//最常用,因为最简洁
命令序列
}

函数定义完之后并不会自动执行,需要调用才行,好处在于可以写一段功能代码作为函数,有需要就直接调用定义的时候哪怕出现语法错误也没关系,不调用就不会报错
当然我们写函数最终目的还是为了调用,为了实现某个功能块

  • 函数返回值:

return表示退出函数并返回一个退出值,脚本中可以用$?变量显示该值
使用原则

  1. 函数一结束就取返回值,因为$?变量只返回执行的最后一条命令的退出状态码
  2. 退出状态码必须是0~255,超出时值将为256取余

1.函数的调用

直接再脚本里定义函数的代码块后写函数名即可完成调用

#这是规范的写法
#!/bin/bash
function fun1 {		//定义了一个函数叫做fun1
echo "this is a function"
}


#这是简洁的写法
#!/bin/bash
f1 () {
echo hello 
}

f2 () {
echo world
}

f3 () {
echo "`f1` `f2`" 
}
f3

2.例:

  • 部署本地yum源
[root@c7-1 home]# vim dome1.sh 

#!/bin/bash
backuprepo (){				//函数名
cd /etc/yum.repos.d			
mkdir repo,bak
mv *.repo repo.bak
mount /dev/sr0 /mnt &>/dev/null
}

makelocalrepo (){
echo
[local]
name=local
baseurl=file:///mnt
enable=1
gpgcheck=0 > local.repo
}

userlocalrepo (){
yum clean all > /dev/null
yum makecache > /dev/null
yum install -y httpd > /dev/null
}

backuprepo			//调用
makelocalrepo		//调用
userlocalrepo		//调用

3.函数的作用范围

在 Shell 脚本中函数的执行并不会开启一个新的子Shell,而是仅在当前定义的Shell 环境中有效。
如果Shell脚本中的变量没有经过特殊设定,默认在整个脚本中都是有效的。
在编写脚本时,有时需要将变量的值限定在函数内部,可以通过内置命令local来实现。
函数内部变量的使用,可以避免函数内外同时出现同名变量对脚本结果的影响。
shell脚本中变量默认全局有效
local命令:将变量限定在函数内部使用

[root@c7-1 home]# vim dome4.sh 

#!/bin/bash
myfunc () {
local a
a=8
echo $a

}
a=9
myfunc
echo $a


[root@c7-1 home]# bash dome4.sh 
8
9

#上述脚本中myfun函数内部使用了local命令设置变量a,其作用是将变量a限定在函数内部。
#myfun函数外部同样定义了变量i,内部变量a和全局变量i互不影响。
#脚本执行时先调用了函数myfun,函数内部变量a为8,所以输出结果是8。
#调用完函数之后,给变量a赋值为9,再打印外部变量i,所以又输出9

  • 阶乘
[root@c7-1 home]# vim dome5.sh 

#!/bin/bash
fa () {        		//定义函数名字fa
if [ $1 -eq 1 ]		//判断$1(第一个位置)是否等于1
then				//为真则
        echo 1		//打印 1
else				//条件不满足,为假则
        local tp=$[ $1 - 1 ]	//限定在函数内部使用
        local res=$(fa $tp)
        echo $[ $1 * $res ]		//打印$1x$res
fi					//结束判断
}
read -p "请输入:" n
res=$(fa $n)	//调用函数fa 	
echo $res		//打印结果

[root@c7-1 home]# bash dome5.sh 
请输入:5
120

#上述脚本中先运行交互式变量,$n,根据你输入的数字调用函数fa,
#先if判断我输入的数是否等于1,我输入的5,不等于1,条件为假,运行else
#然后定义tp变量 $1 -1 也就是 5-1 得出4 ;定义res变量,在把tp的值 4 调用给fa;他俩都是内部变量
#然后echo $1 也就是5,乘 $res 4;只有自上而下运行完所有命令 才会再次用$res的调用tp,继续判断$tp是否等于1,直至5-1=4 4-1=3 3-1=2 2-1=1;
#所以5x4x3x2x1=120

五、数组

1.数组的定义

数组是存放相同类型数据的集合,在内存中开辟了连续的空间,通常配合循环使用

2.数组的定义方式

A="1 2 3 456"     //定义字符串
A=(1 2 3 4 567)		//定义数组
   0 1 2 3 4		//其下标示

2.1 第一种方式

直接把要加入数组的元素用小括号括起来,中间用空格分开

数组名=(value0 value1 value2)

num=(11 22 33 44)
${#num}     //显示字符串长度

[root@c7-1 home]# echo ${num[*]}
11 22 33 44

2.2 第二种方式

精确的给每一个下标索引定义一个值加入数组,索引数字可以不连续

数组名=([0]=value [1]=value [2]value ...)

num=([0]=55 [1]=66 [2]77 [4]88)

[root@c7-1 home]# echo ${num[*]}
[0]55 [1]66 [2]77 [3]88

2.3 第三种方式

先把要加入数组的元素全部先赋值给一个变量,然后引用这个变量加入到数组

列表名="value0 value1 value2...."
数组名=($列表名)

list="11 12 13 14"
num=($list)

2.4 第四种方式

根据下标定义

数组名[0]="11"
数组名[0]="22"
数组名[0]="33"

数组名[0]="value"
数组名[0]="value"
数组名[0]="value"

2.5 元素切片

[root@c7-1 home]# arr=(1 2 3 4 5 6 7 8 9)	//定义数组
[root@c7-1 home]# echo ${arr[*]:2:3}		//切片只读取2后面的3个数
3 4 5

2.6 元素替换

[root@c7-1 home]# echo ${arr[*]/4/90}		//把4修改成90
1 2 3 90 5 6 7 8 9

2.6 元素删除

[root@c7-1 home]# unset arrt[4]		//删除是以下标来删除
[root@c7-1 home]# echo ${arr[*]}
1 2 3 4 5 6 7 8 9

六、冒泡排序

[root@c7-1 home]# vim domem.sh 

        #确定比较元素的位置,比较相邻的两个元素,较大的数往后放,小的往前放,并且每轮比较次数要随着轮>
数递减
        for ((j=0;j<$lt-i;j++))
        do
                #定义第一个元素的值
                first=${array[$j]}

                #定义第二个元素的值
                k=$[$j+1]
                second=${array[$k]}

                #如果第一个元素比第二个元素大就互换
                if [ $first -gt $second ]
                then
                        #把第一个元素值保存到临时变量里面
                        tmp=$first

                        #把第二个元素值保存到第一个元素
                        array[$j]=$second

                        #把第三个元素值保存到第二个元素
                        array[$k]=$tmp
                fi
        done

done
echo "new_array:${array[*]}"

[root@c7-1 home]# bash domem.sh 
old_array:90 70 60 40 50 30
new_array:30 40 50 60 70 90

总结

for语句的结构
while语句的结构
untile语句的结构
Shell函数定义方法
数组使用方法

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值