Shell编程之循环语句示例详解

 更新时间:2023年12月08日 10:45:55   作者:小  
在Shell 脚本开发中,经常碰到一些规范方面的问题,例如忘了便用引号或在 if 语句末尾处忘记加 fi 结束,这篇文章主要介绍了Shell编程之循环语句,需要的朋友可以参考下

一、使用 for 循环语句

1. for 语句的结构

  • 使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每一个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。
  • for 循环语句的语法结构如下
for 变量名 in 取值列表
do
	命令序列
done

上述语句结构中,操作对象为用户指定名称的变量,并通过 in 关键字为该变量预先设置了一个取值列表,多个取值之间以空格进行分隔。位于 do 和 done 之间的命令序列称为“循环体”,其中的执行语句需要引用变量以完成相应的任务。

2. for 语句的执行流程

  • 首先将列表中的第1个取值赋给变量,并执行 do···done 循环体中的命令序列
  • 然后将列表中的第2个取值赋给变量,并执行循环体中的命令序列……
  • 以此类推,直到列表中的所有取值用完,最后将跳至 done 语句,表示结束循环

3. for 语句应用示例

根据姓名列表批量添加用户,操作如下

[root@localhost /home]#vim /opt/user.txt      #用户列表文件
wangwu
zhangsan
lisi
[root@localhost /home]#vim fo2.sh            #批量添加或删除用户脚本
#!/bin/bash
ULIST=$(cat /opt/user.txt)
for UNAME in $ULIST
do
        useradd $UNAME                                       
#        userdel -r $UNAME &>/dev/null
        echo "123456" |passwd --stdin $UNAME &>/dev/null
        echo "创建用户成功"
#       echo "删除用户中...";sleep 2
#       echo "删除成功" 
done
wq保存并退出
#如果想要批量删除用户就可以把上面注释去掉,并把创建用户的命令给注释掉
[root@localhost /home]#. fo2.sh            #测试并确认执行的结果
创建用户成功
创建用户成功
创建用户成功
[root@localhost /home]#tail -3 /etc/passwd
wangwu:x:1001:1001::/home/wangwu:/bin/bash
zhangsan:x:1002:1002::/home/zhangsan:/bin/bash
lisi:x:1003:1003::/home/lisi:/bin/bash

根据 IP 地址列表检查主机状态

[root@localhost /home]#vim /opt/ipadds.txt            #IP地址列表文件
192.168.8.1
192.168.8.2
192.168.8.3
[root@localhost /home]#vim fo3.sh                     #循环检查各主机的脚本
#!/bin/bash
HLIST=$(cat /opt/ipadds.txt)
for IP in $HLIST
do
ping -c 3 -i 0.2 -W 3 $IP &>/dev/null                 #-c是发送ping包的数量为3
        if [ $? -eq 0 ]                               #-i是收发信息的间隔时间为0.2s
then                                                  #-W是超时时间为3s
        echo "HOST $IP is up"
else
        echo "HOST $IP is down"
fi
done
[root@localhost /home]#sh fo3.sh                     #使用sh命令就不用赋予权限才能运行
HOST 192.168.8.1 is up
HOST 192.168.8.2 is up
HOST 192.168.8.3 is down

密码输入正确和错误提示

[root@localhost /home]#vim fo4.sh 
#!/bin/bash
init=123456
for i in {1..3}
do
        read -p "请输入用户密码:" passwd
        if [ $passwd == $init ]
then
        echo "密码正确"
        exit
fi
done
         echo "密码错误"
[root@localhost /home]#sh fo4.sh        
请输入用户密码:1
请输入用户密码:1
请输入用户密码:1
密码错误                                  #密码输入错误三次直接退出交互界面
[root@localhost /home]#sh fo4.sh 
请输入用户密码:123456
密码正确                                  #密码输入成功提示密码输入正确

二、while 循环语句

for 循环语句非常适合于列表对象无规律,且列表来源已固定(如某个列表文件)的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定条件执行重复操作等情况,则更适合使用 while 语句。

1.while 语句的结构

使用 while 循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。但是在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。 循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环。 while循环语句的语法结构如下所示:

2.while 语句的执行流程

首先判断 while 后的条件测试操作结果,如果条件成立,则执行 do···done 循环体中的命令序列返回 while 后再次判断条件测试结果,如果条件仍然成立,则继续执行循环体再次返回到 while 后,判断条件测试结果…如此循环直到 while 后的条件测试结果不再成立为止,最后跳转到 done 语句,表示结束循环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kanpyiRh-1644830523881)(C:\Users\xiaozhu\AppData\Roaming\Typora\typora-user-images\1644829317814.png)]

3. while 语句应用示例

① 批量添加规律编号的用户

[root@localhost /home]#vim useradd.sh                   #批量添加用户脚本
#!/bin/bash
PREFIX="gl"
i=1
while [ $i -le 20 ]
do
  useradd ${PREFIX}$i
  echo "123456"|passwd --stdin ${PREFIX}$i &>/dev/null
  let i++
done
[root@localhost /home]#sh useradd.sh 
[root@localhost /home]#grep "gl" /etc/passwd |tail -3
gl18:x:1021:1021::/home/gl18:/bin/bash
gl19:x:1022:1022::/home/gl19:/bin/bash
gl20:x:1023:1023::/home/gl20:/bin/bash

上述脚本代码中,使用变量 i 来控制用户名称的编号,初始赋值为1,并且当取值大于20时终止循环。在循环中,通过语句 “let i++”(等同于i=‘expr $i+1’)来使变量i的值增加1,因此当执行第一次循环后i的值将变成2,执行第2次循环后i的值将变成3…以此类推。
如果想要删除添加的用户,只需要把 while循环中添加用户的命令序列改为删除用户的操作即可,操作如下:

[root@localhost /home]#vim useradd.sh
#!/bin/bash
PREFIX="gl"
i=1
while [ $i -le 20 ]
do
  userdel -r ${PREFIX}$i
#  echo "123456"|passwd --stdin ${PREFIX}$i &>/dev/null
  let i++
done
[root@localhost /home]#sh useradd.sh 
[root@localhost /home]#id gl20                  #确认用户是否删除成功
id: gl20: no such user

② 猜数字大小

[root@localhost /home]#vim w4.sh 
#!/bin/bash
NUM=8
while true 
do
read -p "请输入数字:" sz
        if [ $sz -eq $NUM ];then
                echo "你猜对了!"
                break
elif [ $sz -gt $NUM ];then
                echo "你猜大了"
elif [ $sz -lt $NUM ];then
                echo "你猜小了"
        fi
done
[root@localhost /home]#sh w4.sh 
请输入数字:2
你猜小了
请输入数字:4   
你猜小了
请输入数字:6
你猜小了
请输入数字:8
你猜对了!

③ 猜价格游戏

[root@localhost /home]#vim w5.sh 
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
a=0
echo "商品实际价格范围为0~999,猜猜价格多少?"
while true
do
read -p "请输入你猜测的价格:" INT
let a++
        if [ $INT -eq $PRICE ];then
        echo "恭喜你猜对了,实际价格是$PRICE"
        echo "你总共猜了 $a次"
        break
elif [ $INT -gt $PRICE ];then
        echo "你猜高了"
   else
        echo "你猜低了"
   fi
done
[root@localhost /home]#sh w5.sh 
商品实际价格范围为0~999,猜猜价格多少?
请输入你猜测的价格:188
你猜低了
请输入你猜测的价格:288
你猜低了
...... 省略
你猜高了
请输入你猜测的价格:920
恭喜你猜对了,实际价格是920
你总共猜了 12次

三、Shell 函数

1.概述

在编写shelI脚本时,你经常会发现在多个地方使用了同一段代码。如果只是一小段代码,一般也无关紧要。但是在shell脚本中多次重写大块代码段就太累人了。为了解决这个问题,我们可以将 shell 脚本代码放进函数中封装起来,这样就能在脚本中的任何地方多次重复使用它了。

2.函数的基本格式

[function] 函数名(){
  命令序列
[return x]                           #return x 的作用是命令序列执行完后返回给系统一个值,可省略  
}
或者
                                     #也可以省略掉[function],它表示该函数的功能
函数名() {                            #函数名后面()是没有内容的
  命令序列                            #我们执行的命令内容放在{}里面
}
  • 函数一结束就取返回值,退出的状态码必须是0~255
  • 由于退出状态码必须小于256,函数的结果必须生成一个小于256的整数值,任何大于256的值都会产生一个错误值。

3. 函数应用示例

定义一个输入两个数求和的脚本

[root@localhost /home]#vim summ.sh
#!/bin/bash
sum(){
read -p "请输入第一个数:" NUM1
read -p "请输入第二个数:" NUM2
echo "你输入的二个数为:$NUM1 和 $NUM2."
SUM=$[$NUM1 + $NUM2]
echo "两个数和为:$SUM"
}
sum
[root@localhost /home]#sh summ.sh 
请输入第一个数:8
请输入第二个数:9
你输入的二个数为:8 和 9.
两个数和为:17

返回值的范围

[root@localhost /home]#vim retun.sh 
#!/bin/bash
function test1 {
read -p "请输入数字:" num
return $[num*2]
}
test1
echo $?
[root@localhost /home]#sh retun.sh 
请输入数字:3
6
[root@localhost /home]#sh retun.sh 
请输入数字:127
254
[root@localhost /home]#sh retun.sh 
请输入数字:128
0

函数的阶乘

[root@localhost /home]#vim cc.sh
#!/bin/bash
fa () {
if [ $1 -eq 1 ]
then
echo 1
else
        local tp=$[ $1 - 1 ]
        local res=$(fa $tp)
        echo $[ $1 * $res ]
fi
}
read -p "请输入:" num
res=$(fa $num)
echo $res
[root@localhost /home]#sh cc.sh      #5*4*3*2*1=120
请输入:5
120
[root@localhost /home]#sh cc.sh      #3*2*1=6
请输入:3
6

四、数组

1. 定义数组

可以在单行中使用数值列表来定义一个数组

array_var=(test1 test2 test3 test4)
#这些值将会存储在以0为起始索引的连续位置上
或者
#将数组定义为一组“索引—值”
array_var=[0]="test1"
array_var=[1]="test2"
array_var=[2]="test3"
array_var=[3]="test4"
array_var=[4]="test5"
array_var=[5]="test6"

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

num=([0]=55 [1]=66 [2]=77 [4]=88)
数组名=([0]=value [1]=value [2]=value. . .)

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

list=“11 12 13 14”
num=($list)

2. 获取数组长度

打印出特定索引的数组元素内容

#echo ${array_var [0]}
test1
index=5
#echo ${array_var[$index]}
test6

以列表形式打印出数组中的所有值

#echo ${array_var[*]}
test1 test2 test3 test4 test5 test6
或者
#echo ${array_var[@]}
test1 test2 test3 test4 test5 test6

打印数组长度(即数组中元素的个数)

#echo ${#array_var[*]}6

数组元素的遍历

[root@localhost ~]#arr=(1 2 3 4 5 6)
[root@localhost ~]#for i in ${arr[*]}
> do
> echo $i
> done
1
2
3
4
5
6

3.元素切片

[root@localhost ~]#arr=(1 2 3 4 5 6 7 8 9)
[root@localhost ~]#echo ${arr[*]}
1 2 3 4 5 6 7 8 9
[root@localhost ~]#echo ${arr[*]:2:3}         #提取出第二个数后面的三个值
3 4 5
[root@localhost ~]#echo ${arr[*]:2:5}
3 4 5 6 7
[root@localhost ~]#echo ${arr[*]:2:2}
3 4
[root@localhost ~]#echo ${arr[*]:0:6}
1 2 3 4 5 6

4.元素替换

[root@localhost ~]#arr=(1 2 3 4 5 6 7 8 9)
[root@localhost ~]#echo ${arr[*]}
1 2 3 4 5 6 7 8 9
[root@localhost ~]#echo ${arr[*]/3/88}      #3指的是查找数主里面的字符,88指的是需要替换的字符
1 2 88 4 5 6 7 8 9
[root@localhost ~]#echo ${arr[*]/5/66}
1 2 3 4 66 6 7 8 9

5.元素删除

[root@localhost ~]#arrt=(1 2 33 4 566 6)
[root@localhost ~]#echo ${arrt[*]}
1 2 33 4 566 6
[root@localhost ~]#unset arrt[2]         #删除的时候是以下标的形式来进行删除,下标2对应的字符为33    
[root@localhost ~]#echo ${arrt[*]}
1 2 4 566 6
[root@localhost ~]#unset arrt[4]         #下标4对应的字符为566
[root@localhost ~]#echo ${arrt[*]}
1 2 4 6

6.冒泡排序

概念: 指的是它会遍历若干次要排序的数列,每次遍历时,它都会从前往后依次的比较相邻两个数的大小;如果前者比后者大,则交换它们的位置。这样,一次遍历之后,最大的元素就在数列的末尾! 采用相同的方法再次遍历时,第二大的元素就被排列在最大元素之前。重复此操作,直到整个数列都有序为止。 案例

[root@localhost /home]#vim mp.sh 
#!/bin/bash
array=(20 40 30 10 60 50)
echo "old_array:${array[*]}"
lt=${#array[*]}
#定义比较轮数,比较轮数为数组长度减1,从1开始;
for ((i=1;i<$lt;i++))
do
#确定比较元素的位置,比较相邻的两个元素,较大的数往后放,小的数往前放,并且每
轮比较次数需要随着轮数递减
        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[*]}"

五、Shell 脚本调试

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

1.echo 命令

echo命令是最有用的调试脚本工具之一,一般在可能出现问题的脚本中加入 echo 命令,采用的是分段排查的方式。

2.bash 命令

除了echo 命令之外,bash Shell 也有相应参数可以调试脚本。

使用 bash 命令参数调试,命令的语法如下:

sh [-nvx] 脚本名

常用的参数如下所示
① -n:不会执行该脚本,仅查询脚本语法是否有问题,如果没有语法问题就不显示任何内容,如果有问题会提示报错。
② -V:在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出错误提示。
③ -x:将执行的脚本内容输出到屏幕上,这是个对调试很有用的参数。

3.set 命令

当脚本较长时,可以使用 set 命令指定调试一段脚本

常用参数如下:

set -x 					#开启调试模式
set +x                  #关闭调试模式

示例

[root@localhost /home]#cat 1.sh 
#!/bin/bash
set -x
for ((i=1;i<=5;i++))
do
	echo $i
done
#开启调试模式以后会看到每段的反馈结果
[root@localhost /home]#sh 1.sh 
+ (( i=1 ))
+ (( i<=5 ))
+ echo 1
1
+ (( i++ ))
+ (( i<=5 ))
+ echo 2
2
+ (( i++ ))
+ (( i<=5 ))
+ echo 3
3
+ (( i++ ))
+ (( i<=5 ))
+ echo 4
4
+ (( i++ ))
+ (( i<=5 ))
+ echo 5
5
+ (( i++ ))
+ (( i<=5 ))

总结

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

3.set 命令

当脚本较长时,可以使用 set 命令指定调试一段脚本

常用参数如下:

set -x 					#开启调试模式
set +x                  #关闭调试模式

示例

[root@localhost /home]#cat 1.sh 
#!/bin/bash
set -x
for ((i=1;i<=5;i++))
do
	echo $i
done
#开启调试模式以后会看到每段的反馈结果
[root@localhost /home]#sh 1.sh 
+ (( i=1 ))
+ (( i<=5 ))
+ echo 1
1
+ (( i++ ))
+ (( i<=5 ))
+ echo 2
2
+ (( i++ ))
+ (( i<=5 ))
+ echo 3
3
+ (( i++ ))
+ (( i<=5 ))
+ echo 4
4
+ (( i++ ))
+ (( i<=5 ))
+ echo 5
5
+ (( i++ ))
+ (( i<=5 ))

总结

Shell 脚本是千变万化的,正所谓条条大路通罗马,shell 脚本中也是如此。一个脚本可以有无数种写法,但是思路都是相通的,只要有了思路脚本就自然会写的很顺畅!

到此这篇关于Shell编程之循环语句的文章就介绍到这了,更多相关Shell循环语句内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • linux shell内置判断语句

    linux shell内置判断语句

    内置判断,成功的时候返回0,不成功返回非零。接下来通过本文重点给大家介绍linux shell内置判断语句,感兴趣的的朋友一起看看吧
    2017-08-08
  • 利用Linux Find命令快速查找文件方法

    利用Linux Find命令快速查找文件方法

    这篇文章主要介绍了利用Linux Find命令快速查找文件方法,这篇文章应用最多的就是linux find命令进行快速查找定位,本文给大家介绍了find 命令基本使用方法,需要的朋友可以参考下
    2022-12-12
  • shell脚本实现监控shell脚本的执行流程及变量的值

    shell脚本实现监控shell脚本的执行流程及变量的值

    这篇文章主要介绍了shell脚本实现监控shell脚本的执行流程及变量的值本文使用shell完成对执行过程中条件语句中的变量的变化的监控和整个程序的执行流程的观察功能,需要的朋友可以参考下
    2015-03-03
  • Linux 中可重入函数与不可重入函数详解

    Linux 中可重入函数与不可重入函数详解

    这篇文章主要介绍了Linux 中可重入函数与不可重入函数详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • Linux 中 CURL常用命令详解

    Linux 中 CURL常用命令详解

    这篇文章主要介绍了Linux 中 CURL常用命令详解,需要的朋友可以参考下
    2015-10-10
  • shell检测某个文件/文件夹是否存在详细实例

    shell检测某个文件/文件夹是否存在详细实例

    shell是一个用 C 语言编写的程序,它是用户使用Linux的桥梁,下面这篇文章主要给大家介绍了关于shell检测某个文件/文件夹是否存在的相关资料,需要的朋友可以参考下
    2023-06-06
  • Linux bash删除文件中含“指定内容”的行功能示例

    Linux bash删除文件中含“指定内容”的行功能示例

    这篇文章主要介绍了Linux bash删除文件中含“指定内容”的行功能,结合具体实例形式分析了Linux bash删除文件指定内容的实现原理与相关操作技巧,需要的朋友可以参考下
    2017-06-06
  • Linux文件处理常用命令操作技巧

    Linux文件处理常用命令操作技巧

    我是Linux初学者,在这里小编给大家分享linux几个常用文件处理命令,感兴趣的朋友参考下吧
    2017-08-08
  • Shell自动化配置SSH免密登录和取消SSH免密配置脚本

    Shell自动化配置SSH免密登录和取消SSH免密配置脚本

    本文主要介绍了Shell自动化配置SSH免密登录和取消SSH免密配置脚本,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Linux磁盘管理之LVM详解及lvm磁盘操作命令

    Linux磁盘管理之LVM详解及lvm磁盘操作命令

    LVM,Logical Volume Manger,是linux内核提供的一种逻辑卷管理功能,由内核驱动和应用层工具组成,它是在硬盘的分区基础上,创建了一个逻辑层,可以非常灵活且非常方便的管理存储设备,这篇文章主要介绍了Linux磁盘管理之LVM详解及lvm磁盘操作命令,需要的朋友可以参考下
    2023-03-03

最新评论