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