05 shell循环结构



5.1  步进循环语句for
for循环是最简单,也是最常用的循环语句。与其他的程序设计语言一样,for循环都是初学者在学习循环结构时的入门课程。for循环通常用于遍历整个对象或者数字列表。按照循环条件的不同,for循环语句可以分为带列表的for循环、不带列表的for循环以及类C风格的for循环。本节将介绍这3种不同的for循环结构。
5.1.1  带列表的for循环语句

带列表的for循环通常用于将一组语句执行已知的次数,其基本语法如下:
for variable in {list}
do
   statement1
   statement2
   ...
done

在上面的语法中,variable称为循环变量,list是一个列表,可以是一系列的数字或者字符串,元素之间使用空格隔开。
do和done之间的所有的语句称为循环体,即循环结构中重复执行的语句。for循环体的执行次数与list中元素的个数有关。在带列表的for语句的执行时,Shell会将in关键字后面的list列表的第1个元素的值赋给变量variable,然后执行循环体;
当循环体中的语句执行完毕之后,Shell会将列表中的第1个元素的值赋给变量variable,然后再次执行循环体。
当list列表中的所有的元素都被访问后,for循环结构终止,程序将继续执行done语句后面的其他的语句。


#! /bin/bash

#for循环开始
for var in 1 2 3 4 5 6 7 8
do
   #依次输出列表中的数字
   echo "the number is $var"
done

#! /bin/bash

#使用省略的写法表示某个范围
for var in {1..8}
do
   echo "the number is $var"
done

Shell允许用户指定for语句的步长。当用户需要另外指定步长时,其基本语法如下:
for varibale in {start..end..step}
do
   statement1
   statement2
   ...
done


#! /bin/bash

#定义变量,并赋初值为0
sum=0;
#for循环开始,设置起始数值为1,结束数值为100,步长为2
for i in {1..100..2}
do
   #将数累加
   let "sum+=i"
done
echo "the sum is $sum"

#! /bin/bash

#for循环开始
for day in {Mon Tue Wed Thu Fri Sat Sun}
do
   #输出循环变量的值
   echo "$day"
done

#! /bin/bash

#使用ls命令的执行结果作为列表
for file in $(ls)
do
   #输出每个文件名
   echo "$file"
done

#! /bin/bash

#使用通配符作为列表条件
for file in *
do
   echo "$file"
done


#! /bin/bash

#输出所有的参数
echo "$*"
#将参数列表作为条件
for arg in $*
do
   #依次输出各个参数值
   echo "${arg}"
done

5.1.2  不带列表的for循环语句
在某些特殊情况下,for循环的条件列表可以完全省略,称为不带列表的for循环语句。如果没有为for循环提供条件列表,Shell将从命令行获取条件列表。不带列表的for循环语句的一般语法如下:
for variable
do
   statement1
   statement2
   ...
done


由于系统变量$@同样可以获取所有的参数,所以以上的语法等价于以下语法:
for variable in $@
do
   statement1
   statement2
   ...
done


也同样等价于以下语法:
for variable in $*
do
   statement1
   statement2
   ...
done


#! /bin/bash

#不带条件列表
for arg
do
   #输出每个参数
   echo "$arg"
done

5.1.3  类C风格的for循环语句
类C风格的for循环语句的基本语法如下:
for ((expression1; expression2; expression3))
do
   statement1;
   statement2;
   ...
done
在上面的语法中,for循环语句的执行条件被2个圆括号包括起来。
执行条件分为3个部分,由2个分号隔开,第1部分expression1通常时条件变量初始化的语句;
第2部分expression2是决定是否执行for循环的条件。当expression2的值为0时,执行整个循环体;当expression2的值为非0时,退出for循环体。
第3部分,即表达式expression3通常用来改变条件变量的值,例如递增或者递减等。

#! /bin/bash

#for循环开始
for (( i=1;i<5;i++ ))
do
   #输出循环变量i的值
   echo "$i"
done

5.1.4  使用for循环语句处理数组
使用for循环遍历数组非常方便。针对数组,Shell专门提供了一种特殊语法的for循环语句,其基本语法如下:
for variable in ${array[*]}
do
   statement1
   statement2
   ...
done
其中,变量variable是循环变量,in关键字后面的部分表示要遍历的数组,其中array表示数组的名称。在遍历数组的过程中,for循环语句会将每个数组元素的值赋给循环变量variable。因此,用户可以在循环体中对每个数组元素进行相应的操作。


#! /bin/bash

#定义数组
array=(Monday Tuesday Wednesday Thursday Friday Saturday Sunday)
#通过for循环遍历数组元素
for day in ${array[*]}
do
   #输出每个数组元素的值
   echo $day
done

5.2  until循环语句
until循环语句同样也存在于多种程序设计语言中。顾名思义,until语句的作用时将循环体重复执行,直到某个条件成立为止。恰当地使用until语句,可以收到事半功倍地效果。本节将详细介绍until语句的使用方法。

5.2.1  until语句的基本语法
until循环语句的功能是不断地重复执行循环体中的语句,直至某个条件成立。until语句的基本语法如下:
until expression
do
   statement1
   statement2
   ...
done
在上面的语法中,expression是一个条件表达式。当该表达式的值不为0时,将执行do和done之间的语句;当expression的值为0时,将退出until循环结构,继续执行done语句后面的其它的语句。


#! /bin/bash

#定义循环变量i
i=1
#当i的值小于9时执行循环
until [[ "$i" -gt 9  ]]
do
   #计算i的平方
   let "square=i*i"
   #输出i的平方
   echo "$i*$i=$square"
   #循环变量加1
   let "i=i+1"
done

5.2.2  利用until语句批量增加用户

#! /bin/bash

#定义变量i
i=1
#一直循环到变量i的值为21
until [ "$i" -eq 21  ]
do
   #执行useradd命令添加用户
   useradd user$i
   #修改用户密码
   echo "password" | passwd --stdin user$i > /dev/null
   #循环变量自增
   let "i++"
done


#! /bin/bash

i=1
until [ "$i" -eq 21  ]
do
   #依次删除用户
   userdel -r user$i
   let "i++"
done

5.3  while循环语句
while循环是另外一种常见的循环结构。使用while循环结构,可以使得用户重复执行一系列的操作,直到某个条件的发生。这听起来好像跟until循环非常相似,但是与until语句相比,while语句有着较大的区别。本节将详细介绍while语句的使用方法。

5.3.1  while语句的基本语法

while循环语句的基本语法如下:
while expression
do
    statement1
    statement2
    ...
done
在上面的语法中,expression表示while循环体执行时需要满足的条件。虽然可以使用任意合法的Shell命令,但是,通常情况下,expression代表一个测试表达式。与其他的循环结构一样,do和done这2个关键字之间的语句构成了循环体。

5.3.2  通过计数器控制while循环结构

所谓计数器,实际上就是指一个循环变量,当该变量的值在某个范围内时,执行循环体;当超过该范围时,终止循环。

#! /bin/bash

#定义循环变量
i=1
#while循环开始
while [[ "$i" -lt 10  ]]
do
   #计算平方
   let "square=i*i"
   #输出平方
   echo "$i*$i=$square"
   #循环 变量自增
   let "i=i+1"
done

5.3.3  通过结束标记控制while循环结构
在某些情况下,用户可能不知道while循环会执行多少次。此时,用户就无法使用计数器来控制while循环。为了处理这种情况,用户可以在程序中设置一个特殊的标记值,当该标记值出现时,终止while循环。这种特殊的标识值称为结束标记。

#! /bin/bash

#提示用户输入数字
echo "Please enter a number between 1 and 10.Enter 0 to exit."
#读取用户输入的数字
read var
#while循环开始
while [[ "$var" != 0  ]]
do
   #提示用户输入数字太小
   if [ "$var" -lt 5  ]
   then
      echo "Too small. Try again."
      read var
   #提示用户输入数字太大
   elif [ "$var" -gt 5  ]
   then
      echo "Too big. Try again."
      read var;
    else
       echo "Congratulation! You are right."
       exit 0;
    fi
done

5.3.4  理解while语句与until语句的区别
语法结构非常相似,都是将循环条件放在了语句的后面:
while expression
do
...
done

until语句的语法结构如下:
unitl expression
do
...
done
但是,在while语句中,当expression的值为0时才执行循环体中的语句,当expression的值为非0值时,将退出循环体;在until语句中,当expression的值为非0时,执行循环体中的语句,当expression的值为0时,将退出循环结构。因此,用户在使用这2种语句时,一定要注意区分这个关键的地方。


在执行机制方面,这2个语句是相同的,即首先会判断expression的值,当该表达式的值符合要求时,才执行循环体中的语句;否则,都不会执行循环体。

5.4  嵌套循环
在程序设计语言中,嵌套的循环也是一种非常常见的结构。Shell同样也支持嵌套循环。通过嵌套循环,可以完成更复杂的功能。本节将介绍Shell中嵌套循环的使用方法。


#! /bin/bash

#外层循环
for ((i=1;i<=9;i++))
do
    #内层循环
    for ((j=1;j<=i;j++))
    do
            #计算2个数的乘积
            let "product=i*j"
            #输出乘积
            printf "$i*$j=$product"
            #输出空格分隔符
            if [[ "$product" -gt 9  ]]
            then
                printf "   "
            else
                printf "    "
            fi
    done
    echo
done

5.5  利用break和continue语句控制循环
在Shell中的循环结构中,还有2个语句非常有用,即break和continue语句。前者用于立即从循环中退出;而后者则用来跳过循环体中的某些语句,继续执行下一次循环。本节将详细介绍这2个语句的使用方法。

5.5.1  利用break语句控制循环
break语句的作用是立即跳出某个循环结构。break语句可以用在for、while或者until等循环语句的循环体中。


#! /bin/bash

for ((i=1;i<=9;i++))
do
   for ((j=1;j<=i;j++))
   do
      let "product=i*j"
      printf "$i*$j=$product"
      if [[ "$product" -gt 9  ]]
      then
         printf "   "
      else
         printf "    "
      fi
   done
   echo
   #当变量i的值为5时,退出循环
   if [[ "$i" -eq 5  ]]
   then
      break;
   fi
done

#! /bin/bash

for ((i=1;i<=9;i++))
do
   for ((j=1;j<=i;j++))
   do
      let "product=i*j"
      printf "$i*$j=$product"
      if [[ "$product" -gt 9  ]]
      then
         printf "   "
      else
         printf "    "
      fi
      #退出循环
      if [[ "$j" -eq 5  ]]
      then
         break
      fi
   done
   echo
done

#! /bin/bash

for ((i=1;i<=9;i++))
do
   for ((j=1;j<=i;j++))
   do
      let "product=i*j"
      printf "$i*$j=$product"
      if [[ "$product" -gt 9  ]]
      then
         printf "   "
      else
         printf "    "
      fi
      if [[ "$j" -eq 5  ]]
      then
         #增加参数2
         break 2
      fi
   done
   echo
done

5.5.2  利用continue语句控制循环
前面介绍的break语句是退出循环体。而continue语句则比较有趣,它的作用不是退出循环体。而是跳过当前循环体中该语句后面的语句,重新从循环语句开始的位置执行。

#! /bin/bash

for var in {1..10}
do
   #如果当前数字为奇数
   if [[ "$var%2" -eq 1  ]]
   then
      #跳过后面的语句
      continue
   fi
   echo "$var"
done

5.5.3  分析break语句和continue语句的区别
正如前面所讲,break语句和continue语句都可以位于各种循环体内,用于控制当前的循环流程。
但是,break语句是直接退出当前的循环结构,转向执行循环体后面的语句;而continue语句则只是跳过当前循环体中continue语句后面的语句,转向当前循环体的起始位置,重新执行下一次循环,并没有退出当前的循环结构。这是这两者的最本质的区别。
另外, 没有参数的break语句和continue语句都只是影响到本层的循环流程,如果想要影响多层循环,则可以附加数字参数。

#!/bin/sh

#外层循环
for i in a b c d
do
   echo -n "$i "
   #内层循环
   for j in `seq 10`
   do
      if [ $j -eq 5  ];then
         break
      fi
      echo -n "$j "
   done
   echo
done

#!/bin/sh

for i in a b c d
do
   echo -n "$i "
   for j in `seq 10`
   do
      if [ $j -eq 5  ];then
         #指定跳出层数2
         break 2
      fi
      echo -n "$j "
   done
   echo
done

#!/bin/sh

for i in a b c d
do
   echo -n "$i "
   for j in `seq 10`
   do
      if [ $j -eq 5  ];then
         #跳过后面的语句
         continue
      fi
      echo -n "$j "
   done
   echo
done

#!/bin/sh

for i in a b c d
do
   echo -n "$i "
   for j in `seq 10`
   do
      if [ $j -eq 5  ];then
         #使用含有数字参数的continue语句
         continue 2
      fi
      echo -n "$j "
   done
   echo
done


你可能感兴趣的:(#,07shell)