设为首页 收藏本站
查看: 616|回复: 0

[经验分享] Linux基础之bash脚本进阶篇-循环语句(for,while,until)

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-9-7 14:14:01 | 显示全部楼层 |阅读模式
什么是循环语句、死循环?
循环语句:将一段代码重复执行0、1或多次。
到底要重复运行多少次?以及我们如何设定循环语句的重复次数?
为了解决上面的问题于是就有了进入条件与退出条件。
进入条件:条件满足时进入循环。
退出条件:不符合条件退出循环。
一种特殊的循环:死循环
死循环:在编程中,一个无法靠自身的控制终止的循环称为"死循环"。死循环的出现有两种情况:
1、因程序需要刻意写的;2、因程序员的失误造成的。
第二种的死循环通常会造成比较严重的程序错误,甚至会因此而影响物理机。因此死循环的使用需要合理的设计。
                                                         实验环境CentOS7.2


本文重要的三个循环语句:for、while、until
………………………………………………………………………………………………………………………
for循环
for语句的使用格式:
    for NAME in LIST(列表); do
    循环体
    done
列表生成方式:
(1) 整数列表
    {start..end}
    $(seq start [[step]end])
(2) glob
    /etc/rc.d/rc3.d/K*
(3) 命令
………………………………………………………………………………………………………………………
下面以一个例子看看for的具体作用
示例:计算1+2+...+10的值
1
2
3
4
5
6
7
8
9
#!/bin/bash
#sum the value of "1+2+...+10"
#author chawan
#date:20160906
declare -i sum=0
for x in {1..10};do
   let sum+=$x
done
echo "The sum is : $sum"



运行脚本0906-1结果如下

1
2
[iyunv@docker hmworks]# sh 0906-1
The sum is : 55



上面使用了第一种的整数列表中的第一种形式,这里如果是“1+2+...+n”这种形式那么{start..end}就不再适用,此时就只能使用$(seq start [[step]end])。下面再举一个例子说明
示例:计算“1+2+...+n”的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
#sum “1+2+...+n”
#author chawan
#date:20160906
declare -i sum=0
#以交互的方式输入一个正整数
read -p "Please inset a number :" num
#判断输入的数是否为空,为空则提示并退出
[ -z $num ] && echo "Please input a number!" && exit 1
#判断输入的是否是正整数,若是则执行循环,若不是提示输入正整数并退出
if [[ $num =~ ^[1-9][0-9]{0,}$ ]] ; then
   for i in {1..$num};do   
#for i in `seq 1 $num`;do
       let sum+=$i
       #sum=$[$sum+$i] 这种方式也可以不过不够简练
   done
else
  echo "Error : please input a positive integer" && exit 2
fi
#显示最后的和
echo "The sum is : $sum"



下面执行该脚本
1
2
3
4
[iyunv@docker hmworks]# sh 0906-2
Please inset a number :8
0906-2:行14: let: sum+={1..8}: 语法错误: 期待操作数 (错误符号是 "{1..8}")
The sum is : 0



该结果说明{start..end}形式不适用于有变量出现的情况,既然这个不行就来试试$(seq start [[step]end])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
#sum “1+2+...+n”
#author chawan
#date:20160906
declare -i sum=0
#以交互的方式输入一个正整数
read -p "Please inset a number :" num
#判断输入的数是否为空,为空则提示并退出
[ -z $num ] && echo "Please input a number!" && exit 1
#判断输入的是否是正整数,若是则执行循环,若不是提示输入正整数并退出
if [[ $num =~ ^[1-9][0-9]{0,}$ ]] ; then
   for i in `seq 1 $num`;do
       let sum+=$i
       #sum=$[$sum+$i]
   done
else
  echo "Error : please input a positive integer" && exit 2
fi
#显示最后的和
echo "The sum is : $sum"



执行该脚本

1
2
3
4
5
6
[iyunv@docker hmworks]# sh 0906-2
Please inset a number :10
The sum is : 55
[iyunv@docker hmworks]# sh 0906-2
Please inset a number :100
The sum is : 5050



该结果表明$(seq start [[step]end])适用性更好,因此一般建议使用它。
列表的glob与命令这两种就不再具体演示。大家感兴趣可以自己尝试下做个实验体会体会。

………………………………………………………………………………………………………………………
while循环
while语句使用格式:
    while CONDITION; do
    循环体
    done

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环;
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正;

进入条件:CONDITION为true;
退出条件:CONDITION为false
………………………………………………………………………………………………………………………
示例:计算1+2+...+10的值
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#sum the value of "1+2+...+10"  while
#author chawan
#date:20160906
#为了严谨起见,事先声明变量sum及i为整数型
declare -i sum=0
declare -i i=1
while [ $i -le 10 ];do
    let sum+=$i    #sum=$[$sum+$i]的简写形式
    let i++        #不断修正变量体
done
echo "The sum is : $sum"



执行脚本,查看其是否正确执行

1
2
[iyunv@docker hmworks]# sh 0906-3
The sum is : 55



while与for的不同在于:
1、不需要列表,因此可以大大节省内存空间,因为for如果列表很大会占用较多内容空间,对系统性能会造成影响,所以此时while的优越性就显现出来,它不需要占用很多内存空间,只需要两个变量的空间及做加法即可。
2、while需要修正体来不断修正变量,最终在符合退出条件时结束循环。
………………………………………………………………………………………………………………………
until循环
until语句使用格式:
    until CONDITION; do
    循环体
    done

CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为“false”,则执行一次循环;直到条件测试状态为“true”终止循环;
因此:CONDTION一般应该有循环控制变量;而此变量的值会在循环体不断地被修正;
进入条件:CONDITION为false;
退出条件:CONDITION为true
until的用法同while,唯一的区别在于进入循环与退出循环的条件相反。
以相同的例子来体会二者的区别
………………………………………………………………………………………………………………………
示例:计算1+2+...+10的值
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
#sum the value of "1+2+...+10"  until
#author chawan
#date:20160906
declare -i sum=0
declare -i i=1
until [ $i -gt 10 ];do
    let sum+=$i
    let i++
done
echo "The sum is : $sum"



执行脚本,查看结果是否正确输出
1
2
[iyunv@docker hmworks]# sh 0906-4
The sum is : 55



通过比较while与until的唯一差别就在于判断条件。这两者其实算是同一种循环语句,只是进入及退出循环的条件正好相反。


循环控制语句(用于循环体中)
1、continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;
其使用格式:
    while CONDTIITON1; do
      CMD1
        ...
      if CONDITION2; then
       continue
      fi
      CMDn
       ...
    done
………………………………………………………………………………………………………………………
示例:求100以内所有偶数之和;要求循环遍历100以内的所正整数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
#求100以内所有偶数之和;要求循环遍历100以内的所正整数
#author chawan
#date:20160906
declare -i i=1
declare -i sum=0
while [ $i -le 100 ];do
    let i++
#如果为奇数则跳过该循环
    if [ $[${i}%2] -eq 1 ];then
      continue
    fi
    let sum+=$i
done
echo  "The even number sum : $sum"



执行脚本,查看结果是否正确显示

1
2
[iyunv@docker hmworks]# sh 0906-5
The even number sum : 2550




之前我写这个脚本时是这么写的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
#求100以内所有偶数之和;要求循环遍历100以内的所正整数
#author chawan
#date:20160906
declare -i i=1
declare -i sum=0
while [ $i -le 100 ];do
    let sum+=$i
#如果为奇数则跳过该循环,直接进入下一轮判断后面的程序不再执行
    if [ $[${i}%2] -eq 1 ];then
      continue
    fi
    let i++
done
echo  "The even number sum : $sum"



这就是我个人由于对continue的理解不够准确而造成的死循环。
由于continue是跳过其所在循环,直接进入下一轮判断,后面的语句都不再执行。
当时没注意这点所以错误地把i++放在后面,这就导致若i起始值为奇数那么它就一直在重复执行。
这里只要将let sum+=$i与let i++调换为止即可正确执行。
………………………………………………………………………………………………………………………
2、break [N]:提前结束循环;
其使用格式:
    while CONDTIITON1; do
      CMD1
       ...
      if CONDITION2; then
         break
      fi
      CMDn
       ...
    done
break的使用通常是与死循环同时出现的,下面来介绍如何创建死循环

创建死循环:
    while true; do
     循环体
    done

    until false; do
     循环体
    done
………………………………………………………………………………………………………………………
示例:每隔3秒钟到系统上获取已经登录的用户的信息;如果docker登录了,则记录于日志中,并退出;
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#每隔3秒钟到系统上获取已经登录的用户的信息;如果docker用户登录,则记录于日志中,并退出脚本
#author chawan
#date:20160906
while true;do
     if who | grep "^docker\>" $> /dev/null;then
         break
     fi
     sleep 3
     echo "docker is not login"
done
echo "docker logged on." >> /tmp/user.log



运行脚本

1
2
3
4
5
6
7
[iyunv@docker hmworks]# sh 0906-6
docker is not login
docker is not login
docker is not login
docker is not login
docker is not login
docker is not login



为了验证该脚本,下面我们使用docker用户登陆
wKiom1fOxNDjKdg8AAA43X5AK3w176.jpg
wKiom1fOxNDggGm0AABazt_e-04945.jpg
wKioL1fOxNCQuQH2AAALsOuQOWI360.jpg
docker用户登陆后查看/tmp/user.log文件
wKioL1fOxNCQMHjGAAAJkfdg2OE565.jpg



循环语句的特殊用法(while及for)
while循环的特殊用法(遍历文件的每一行):
其使用格式:
    while read line; do
      循环体
    done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
………………………………………………………………………………………………………………………
示例:找出其ID号为偶数的所有用户,显示其用户名及ID号;
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
#找出其ID号为偶数的所有用户,显示其用户名及ID号
#author chawan
#date:20160906
while read line;do
  if [ $[`echo $line | cut -d: -f3`%2] -eq 0 ];then
    echo -e -n "username: `echo $line|cut -d: -f1`\t"
    echo "uid:`echo $line|cut -d: -f3`"
  fi
done < /etc/passwd



运行脚本

wKiom1fOxvHyCEm2AAA1-ZyutMI547.jpg
………………………………………………………………………………………………………………………
for循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do
    循环体
done

控制变量初始化:仅在运行到循环代码段时执行一次;
条件判断表达式:在什么条件下进行循环;
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断;
示例:求100以内所正整数之和
1
2
3
4
5
6
7
8
9
#!/bin/bash
#求100以内所正整数之和
#author chawan
#date:20160906
declare -i sum=0
for ((i=1;i<=100;i++));do
     let sum+=$i
done
echo "The sum is : $sum"



运行脚本,查看结果是否正确
1
2
[iyunv@docker hmworks]# sh 0906-8
The sum is : 5050



for的这种格式减少了代码量,看着更简洁,不过其限制是只适用于有数字出现的循环,若是对某目录下的所有文件进行某种循环的执行就不适应了。

循环嵌套
在本文的最后再以一题体会下循环嵌套的神奇

示例:打印九九乘法表
1
2
3
4
5
6
7
8
9
10
#!/bin/bash
#打印九九乘法表
#author chawan
#date : 20160906
for((j=1;j<=9;j++));do
   for((i=1;i<=j;i++))do
      echo -e -n "${i}X${j}=$[$i*$j]\t"
   done
echo
done



    我在刚刚接触循环嵌套时各种晕,循环嵌套不是没有目的的乱用,而是根据自己的需求有目的的使用,比如要打印99乘法表,开始要分析99乘法表的规律,分析后我们发现它横行是连续的,因此要用到一个循环(通常在遇到连续的内容都会用到循环)它的列也是连续的,因此又用到一个循环,而99乘法表又是由两个变化的量构成,综上我们就可以确定,需要使用两个变量,这两个变量分别要用到循环,而一个变量又受到另一个变量的限制,因此这个受限的变量就是被嵌套的主。问题分析到这里,我们解决这个问题要用到的工具都找出来了:两个变量,每个变量对应一个循环,同时一个变量受到另一个变量的限制,也就是说它需要在其循环内进行嵌套。
    下面就是靠自己去使用工具解决问题了。我相信大家这点应该都不成问题,问题就分析到这里。



小结:
    本文主要介绍什么是循环,死循环,bash常用的三种循环语句for、while、until及循环控制语句continue、break
    在本文结尾又介绍了while的特殊用法(遍历文件中的每一行),for的c语言格式。
至于什么时候用for什么时候用while需要自己在实际写脚本中细细比较,鉴于本人也是新手,这里就算想细说也只能望洋兴叹。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-269009-1-1.html 上篇帖子: DNS高速缓存搭建原理 下篇帖子: 单网卡多IP,双网卡实现负载 Linux
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表