Skip to content

循环

for 循环

带列表的 for 循环

带列表的 for 循环用于执行一定次数的循环(循环次数等于列表元素个数),其语法结构如下:

1
2
3
4
for VARIABLE in (list)
do
    command
done

下面的例子可循环打印出 John 喜爱的水果:

1
2
3
4
5
6
7
#!/bin/bash

for FRUIT in apple orange banana pear
do
    echo "$FRUIT  is John's favorite"
done
echo "No more fruits"

运行结果:

1
2
3
4
5
6
➜  nocilantro bash fruit01.sh 
apple  is John's favorite
orange  is John's favorite
banana  is John's favorite
pear  is John's favorite
No more fruits

上面脚本的写法并不是最好的,因为一旦列表元素改变了,你就不得不去改相应的 for 循环语句块。
好的习惯是将列表定义为一个变量,然后在 for 中使用该变量。
按照这种方法可以将上面的脚本修改成下面的形式:

1
2
3
4
5
6
7
8
#!/bin/bash

fruits="apple orange banana pear"
for FRUIT in ${fruits}
do
    echo "$FRUIT  is John's favorite"
done
echo "No more fruits"

如果列表是数字,常规的方法是使用列表列出所有可能的数值,for 循环会便利所有列出的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

for VAR in 1 2 3 4 5
do
    echo "Loop $VAR times"
done
# Loop 1 times
# Loop 2 times
# Loop 3 times
# Loop 4 times
# Loop 5 times

如果只是少数的几个数字还是比较方便一一枚举出来的,但是如果是 1 到 100,这么写就不实际了,Shell 提供了用于计数的方式,比如说上例中 1 到 5 可以用{1..5}表示。
所以脚本可以改写成下面的格式,运行结果和之前一致

1
2
3
4
5
6
#!/bin/bash

for VAR in {1..5}
do
    echo "Loop $VAR times"
done

还可以使用seq命令结合命令替换的方式生成列表,下面的例子可以针对 1 到 100 的求和进行计算,其中的命令替换部分还可以使用$()代替

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/bin/bash

sum=0
# for VAR in `seq 1 100`
for VAR in $(seq 1 100)
do
    let "sum+=VAR"
done
echo "Total: $sum"
# Total: 5050

下面是利用 seq 命令的“步长”计算 1 到 100 内的奇数和

1
2
3
4
5
6
7
8
9
#!/bin/bash

sum=0
for VAR in $(seq 1 2 100)
do
    let "sum+=VAR"
done
echo "Total: $sum"
# Total: 2500

从上面的命令替换的例子可以看出,其实列表 for 循环中 in 后面的内容可以是任意命令的标准输出。
下面的例子中,会利用 ls 的输出作为 in 的列表,并循环打印所有文件的属性。

1
2
3
4
5
6
#!/bin/bash

for VAR in $(ls)
do
    ls -l $VAR
done

不带列表的 for 循环

1
2
3
4
for VARIABLE
do
    command
done

既然没有列表,那么如何向这个 for 循环传递变量值呢?
实际上,使用不带列表的 for 循环时,需要在运行脚本时通过参数的方式给 for 循环传递变量值

1
2
3
4
5
6
7
8
9
#!/bin/bash

for VARIABLE
do
    echo -n "$VARIABLE "
done
echo
bash for_list06.sh 1 2 3
1 2 3 

该语法虽然可以工作,但是可读性较差,所以不建议使用。
可利用特殊变量$@改写上述结构,使其变成下面的形式,功能是完全一样的。

1
2
3
4
5
6
7
#!/bin/bash

for VARIABLE in $@
do
    echo -n "$VARIABLE "
done
echo

类 C 的 for 循环

Shell 支持类 C 的 for 循环。
了解 C 语言一定会对(i=1;i<=10;i++)这样的结构十分熟悉,在 Shell 中其语法结构如下:

1
2
3
4
for ((expression1; expression2; expression3))
do
    command
done

其中,expression1 为初始化语句,一般用作变量定义和初始化;
expression2 为判断表达式,用于测试表达式返回值并以此控制循环,返回值为真则循环继续,返回值为假时则退出循环;
expression3 用户变量值修改,从而影响 expression2 的返回值,并以此影响循环行为。
下面的脚本演示了使用 for 语句控制的 10 次循环

1
2
3
4
5
6
7
8
#!/bin/bash

for ((i=1;i<=10;i++))
do
    echo -n "$i "
done
echo
# 1 2 3 4 5 6 7 8 9 10 

使用类 C 的 for 循环还有其他的好处:可以在初始化 expression1 的同时初始化多个变量,另外,还可以在 expression3 中同时修改多个变量的值,每个 expression 中的多条语句之间使用逗号隔开。示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash

for ((i=1,j=100;i<=10;i++,j--))
do
    echo "i=$i j=$j "
done
# i=1 j=100 
# i=2 j=99 
# i=3 j=98 
# i=4 j=97 
# i=5 j=96 
# i=6 j=95 
# i=7 j=94 
# i=8 j=93 
# i=9 j=92 
# i=10 j=91 

下面是使用类 C 的 for 循环的示例,在该示例中同时计算了 1 到 100 的和以及 1 到 100 的奇数和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/bin/bash

sum01=0
sum02=0
for ((i=1,j=1;i<=100;i++,j+=2))
do
    let "sum01+=i"
    if [ $j -lt 100 ]; then
        let "sum02 += j"
    fi
done
echo "sum01=$sum01"
echo "sum02=$sum02"
# sum01=5050
# sum02=2500

while 循环

while 循环的语句