Bash Shell中主要提供了三种循环方式:for
、while
和until
一、for循环
与其他编程语言类似,Shell支持for循环。for循环的运作方式,是将串行的元素意义取出,依序放入指定的变量中,然后重复执行含括的命令区域(在do和done 之间),直到所有元素取尽为止。
其中,串行是一些字符串的组合,彼此用$IFS所定义的分隔符(如空格符)隔开,这些字符串称为字段。for循环一般格式为:
for 变量 [in 串行]
do
command..
command..
command..
done
#命令行终端写法
for 变量 in 串行; do command1;command2 done
#支持C语言风格,可以指定步长
for ((初始值;条件;步长))
do
command..
command..
command..
done
案例1:Shell打印执行目录的目录树tree
自己写一个脚本,实现和tree
命令一样可以将自动目录打印成可视化的文件数的功能。
#!/bin/bash
#使用位置参数传入要打印的目录
BASE_PATH=$1
# when the input path is empty or cannot find ,then throw an error
if [ ! -n "$BASE_PATH" -o ! -e "$BASE_PATH" ]; then
echo "ERROR PATH $BASE_PATH"
exit 1;
fi
echo $BASE_PATH
visitDeep=-1;
#定义一个递归函数,递归的调用自己实现对文件夹的遍历
listPath(){
let visitDeep++;
#接收参数
local path=$1
files=`ls $path`
for f in $files; do
deep=0;
while [ $deep -lt $visitDeep ]; do
if [ $deep -eq $[$visitDeep-1] ]; then
printf "├──"
else
printf "│"
fi
let deep++;
done
file="$path/$f"
#如果是普通文件就直接打印出来
if [ -f "$file" ]; then
echo -e " $f"
elif [ -d "$file" ]; then
#如果是目录:先打印目录名,之后递归调用
echo -e " $f"
listPath "$path/$f"
fi
done
let visitDeep--
}
listPath $BASE_PATH
执行结果【部分】:
二、while循环
在案例一种我们在打印文件目录树中也是用了while循环。while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。while循环的语法:
while condtion
do
command1
command2
done
案例二:使用while实现从1加到n,n由用户输入,并且输出最终的和
#!/bin/bash
read -p "Please input the number you want add to: " end
sum=0
i=1
while [ i le end ]; do
let sum=sum+i;
let i++;
done
echo "1+...+$end=$sum"
执行结果:
无限循环的语法格式:
(1)写法一:使用一个:
作为条件,就可以实现无限循环
while :
do
command1
...
done
(2)写法二:使用true
关键字
while true
do
command1
...
done
(3)写法三:使用for语句的C风格
#这是一种C语言风格的写法,在C语言中for(;;)这就是一个无限循环
for ((;;))
三、until循环
until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。until 语法格式:
until condition
do
command1
command2
done
案例三:使用until打印九九乘法表
#!/bin/bash
a=1
b=1
#until 当条件执行为真时跳出循环,和while正好相反
until [ $a -gt 9 ]; do
until [ $b -gt $a ]; do
let c=a*b
echo -n "$a*$b=$c"
let b++
done
let a++
let b=1
echo ""
done
执行结果:
四、跳出循环
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break
和continue
。
1、break命令
break关键字的语法:
break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。
案例四:Shell脚本和用户交互
#!/bin/bash
while :
do
read -p "输入 1 到 5 之间的数字:" aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
"")
#啥都没有输入,不管
;;
*) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
break
;;
esac
done
执行结果:
案例五:使用break跳出2层循环
#!/bin/bash
i=0
while ((++i)); do #外层循环
j=0;
while ((++j)); do #内层循环
if((i>4)); then
break 2 #跳出内外两层循环,在这里和break效果一样
fi
if((j>4)); then
break #跳出内层循环
fi
printf "%-4d" $((i*j))
done
printf "\n"
done
执行结果:
2、continue命令
continue 关键字的语法为:
continue n
n 表示循环的层数:
- 如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
- 如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环同时执行了不带 n 的 continue。这么说可能有点难以理解,稍后我们通过代码来演示。
#!/bin/bash
for((i=1; i<=5; i++)); do
for((j=1; j<=5; j++)); do
if((i*j==12)); then
continue 2
fi
printf "%d*%d=%-4d" $i $j $((i*j))
done
printf "\n"
done
执行结果:
从运行结果可以看出,遇到continue 2
时,不但跳过了内层 for 循环,也跳过了外层 for 循环。
break 和 continue 的区别
break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。