Shell编程之循环语句与函数

1. 循环语句

1.1 for循环语句

使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。在这里,“取值列表”称为 for 语句的执行条件,其中包括多个属性相同的对象,需要预先指定(如通讯录、IP 黑名单)。

for 循环语句的语法结构

for 变量名 in 取值列表
do
命令序列
done

在这里插入图片描述
示例1:创建用户

#!/bin/bash
UL=$(cat /root/users.txt)
for UA in $UL
do
    useradd $UA
    echo "12456" |passwd --stdin &> /dev/null
     echo "已创建$UA"
done 

示例2:根据 IP 地址列表检查主机状态

#!/bin/bash
HY=$(cat /root/ip.txt)
for IP in $HY
do
ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
if [ $? -eq 0 ]
  then
    echo "Host $IP is up!"
  else
    echo "Host $IP is down!"
fi
Done

1.2 While语句的结构

for 循环语句非常适用于列表对象无规律,且列表来源已固定(如某个列表文件)的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定条件执行重复操作等情况, 则更适合使用另外一种循环——while 语句。
使用 while 循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。
while 循环语句的语法结构

while 条件测试操作
do
命令序列
done

在这里插入图片描述
示例1:创建20个用户

#!/bin/bash
RT="lo"
i=1
while [ $i -le 20 ]
do
     useradd ${RT}$i
     echo "123456" |passwd --stdin ${RT}$i &>/dev/null
     echo "已创建${RT}$i"
     let i++
Done

示例2:猜价格

#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格范围为 0-999,猜猜看是多少
?" while true
do
read -p "请输入你猜测的价格数目:" INT let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜你答对了,实际价格是 $PRICE" echo "你总共猜测了 $TIMES 次"
exit 0
elif [ $INT -gt $PRICE ] ; then echo "太高>了!"
else
echo "太低了!"
fi 
done

1.3 Until语句的结构

until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环。

until 循环语句的语法结构

until 条件测试操作
do
命令序列
done

在这里插入图片描述
示例:算50一下的总和

#!/bin/bash
i=0;s=0
until [ $i -eq 50 ]
do
   let "i=$i+1";let "s=$i+$s"
done
  echo 'sum(1....50)'=$s

2. shell函数

Shell 函数可用于存放一系列的指令。在 Shell 脚本执行的过程中,函数被置于内存中, 每次调用函数时不需要从硬盘读取,因此运行的速度比较快。在 Shell 编程中函数并非是必须的元素,但使用函数可以对程序进行更好的组织。将一些相对独立的代码变成函数,可以提高程序可读性与重用性,避免编写大量重复代码。
Shell 函数定义的方法

1. [function] 函数名() {
命令序列
[return x]
}

2.函数名()
{
命令序号
}
  1. “function”关键字表示定义一个函数,可以省略

  2. “{”符号表示函数执行命令的入口,该符号可以>与函数名同行也可以在函数名下一行 的句首;

  3. “}”符号表示函数体结束,两个大括号之间{ }是
    函数体;

  4. “命令序列”部分可以是任意的 Shell 命令,也>可以调用其他函数;

  5. “return”表示退出函数返回一个退出值,通过返回值判断执行是否成功,也可以使用 exit 终止>整个 Shell 脚本。

2.1 编写用户自定义函数

servicectl_usage () {
echo "Usage:servicectl <service-name> <start|stop|restart|reload|status>"
return 1

chk_centos_ver () {
grep "CentOS.*release 7." /etc/centos-release &> /dev/null && echo "7" 
grep "CentOS.*release 6." /etc/centos-release &> /dev/null && echo "6" 
grep "CentOS.*release 5." /etc/centos-release &> /dev/null && echo "5"
}

servicectl () {
[[ -z $1 || -z $2 ]] && servicectl_usage
[ $(chk_centos_ver)=="7" ] && systemctl $2 ${1}.service || service $1 $2
}

2.2 函数变量的作用范围

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

myfun ()
{
local i 
i=8 
echo $i
}
i=9 
myfun 
echo $i
[root@localhost ~]# chmod +x fun_scope.sh
[root@localhost ~]# ./fun_scope.sh
8
9

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

2.3 递归函数

调用自己本身的函数

函数的参数的用法

函数名称 参数 1 参数 2 参数 3 ......

示例:递归遍历目录

function list_files()
{
   for f in `ls $1`;
   do
        if [ -d "$1/$f" ]; then
          echo "$2$f"
          list_files "$1/$f" "  $2"
        else
          echo "$2$f"
        fi
    done
}
list_files "/var/log" ""

3. shell数组

在 Shell 脚本中,数组是一种常见的数据结构,主要的应用场景包括:获取数组长度、获取元素长度、遍历元素、元素切片、元素替换、元素删除等等。Shell 中的数组与 Java、C、Python 不同,只有一维数组,没有二维数组。数组元素的大小与限制,也不需要事先定义。Shell 数组用括号()来表示,元素用空格分隔,元素的下标与大部分编程语言类似从 0 开始。

3.1 数组的定义方式

方法一:
数组名=(value0 value1 value2 …)

方法二:
数组名=([0]=value [1]=value [2]=value …)

方法三:
列表名=”value0 value1 value2 …”数组名=($列表名)

方法四:
数组名[0]=”value”
数组名[1]=”value”
数组名[2]=”value”

  1. 获取数组长度
[root@localhost ~]# arr_number=(1 2 3 4 5) 
[root@localhost ~]# arr_length=${#arr_number[*]} 
[root@localhost ~]# echo $arr_length
5
[root@localhost ~]# arr_length_1=${#arr_number[@]}
[root@localhost ~]# echo $arr_length_1
5
  1. 读取某下标赋值
[root@localhost ~]# arr_index2=${arr_number[2]}	//第三个元素[root@localhost ~]# echo $arr_index2
3
  1. 数组遍历
#!/bin/bash 
arr_number=(1 2 3 4 5) 
for v in ${arr_number[@]} 
do
echo $v 
done
[root@localhost ~]# chmod +x array_traverse.sh
[root@localhost ~]# ./array_traverse.sh
1
2
3
4
5
  1. 数组切片
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# echo ${arr[@]}	//输出整个数组
1 2 3 4 5
[root@centos-7 ~]# echo ${arr[@]:0:2}	//${数组名[@或*]:起始位置:长度} 
1 2
[root@centos-7 ~]# echo ${arr[@]:2:3}
3 4 5
  1. 数组替换
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# echo ${arr[@]/4/66}	//${数组名[@或*]/查找字符/替换字符} 
1 2 3 66 5
[root@centos-7 ~]# echo ${arr[@]}	//并不会替换数组原有内容
1 2 3 4 5
[root@centos-7 ~]# arr=(${arr[@]/4/66})	//要实现改变原有数组,可通过重新赋值实现
[root@centos-7 ~]# echo ${arr[@]}
1 2 3 66 5
  1. 数组删除
[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# unset arr	//删除数组
[root@centos-7 ~]# echo ${arr[*]} 

[root@centos-7 ~]# arr=(1 2 3 4 5)
[root@centos-7 ~]# unset arr[2]	//删除第三个元素
[root@centos-7 ~]# echo ${arr[*]}
1 2 4 5

4. shell脚本调试

在 Shell 脚本开发中,经常碰到一些规范方面的问题,例如忘了使用引号或在 if 语句末尾处忘记加 fi 结束。要注意把复杂的脚本简单化,要思路清晰,并且分段实现。当执行脚本时出现错误后,不要只看那些提示的错误行,而是要观察整个相关的代码段。为避免编写的脚本出错,除了在编写脚本时注意书写规范,排除语法错误,更重要的是 利用调试脚本工具来调试脚本。echo 命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入 echo 命令,采用的是分段排查的方式。除了 echo 命令之外,bash Shell 也有相应参数可以调试脚本。使用 bash 命令参数调
命令的语法为:

sh [-nvx] 脚本名

Set命令   
Set -x :开启调节模式   
Set +x :关闭调节模式

常用参数的具体含义为:
-n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任 何内容,如果有问题会提示报错。

-v:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也 会给出错误提示。

-x:将执行的脚本内容输出到屏幕上,这个是对调试很有用的参数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值