循环

    while循环有一个判断条件,只要符合条件,就不断循环执行指定的语句。

    上面代码中,只要满足条件condition,就会执行命令commands。然后,再次判断是否满足条件condition,只要满足,就会一直执行下去。只有不满足条件,才会退出循环。

    循环条件condition可以使用test命令,跟if结构的判断条件写法一致。

    1. #!/bin/bash
    2. number=0
    3. while [ "$number" -lt 10 ]; do
    4. echo "Number = $number"
    5. number=$((number + 1))
    6. done

    上面例子中,只要变量$number小于10,就会不断加1,直到$number等于10,然后退出循环。

    关键字do可以跟while不在同一行,这时两者之间不需要使用分号分隔。

    1. while true
    2. do
    3. echo 'Hi, while looping ...';
    4. done

    上面的例子会无限循环,可以按下 Ctrl + c 停止。

    while循环写成一行,也是可以的。

    1. $ while true; do echo 'Hi, while looping ...'; done

    while的条件部分也可以是执行一个命令。

    1. $ while echo 'ECHO'; do echo 'Hi, while looping ...'; done

    上面例子中,判断条件是echo 'ECHO'。由于这个命令总是执行成功,所以上面命令会产生无限循环。

    while的条件部分可以执行任意数量的命令,但是执行结果的真伪只看最后一个命令的执行结果。

    1. $ while true; false; do echo 'Hi, looping ...'; done

    上面代码运行后,不会有任何输出,因为while的最后一个命令是false

    until 循环

    until循环与while循环恰好相反,只要不符合判断条件(判断条件失败),就不断循环执行指定的语句。一旦符合判断条件,就退出循环。

    1. until condition; do
    2. commands
    3. done

    关键字do可以与until不写在同一行,这时两者之间不需要分号分隔。

    1. until condition
    2. do
    3. commands
    4. done

    下面是一个例子。

    1. $ until false; do echo 'Hi, until looping ...'; done
    2. Hi, until looping ...
    3. Hi, until looping ...
    4. Hi, until looping ...
    5. ^C

    上面代码中,until的部分一直为false,导致命令无限运行,必须按下 Ctrl + c 终止。

    上面例子中,只要变量number小于10,就会不断加1,直到number大于等于10,就退出循环。

    1. until cp $1 $2; do
    2. echo 'Attempt to copy failed. waiting...'
    3. sleep 5
    4. done

    上面例子表示,只要cp $1 $2这个命令执行不成功,就5秒钟后再尝试一次,直到成功为止。

    until循环都可以转为while循环,只要把条件设为否定即可。上面这个例子可以改写如下。

    1. while ! cp $1 $2; do
    2. echo 'Attempt to copy failed. waiting...'
    3. sleep 5
    4. done

    一般来说,until用得比较少,完全可以统一都使用while

    循环用于遍历列表的每一项。

    1. for variable in list
    2. do
    3. done

    上面语法中,for循环会依次从list列表中取出一项,作为变量variable,然后在循环体中进行处理。

    关键词do可以跟for写在同一行,两者使用分号分隔。

    1. for variable in list; do
    2. commands
    3. done

    下面是一个例子。

    1. #!/bin/bash
    2. for i in word1 word2 word3; do
    3. echo $i
    4. done

    上面例子中,word1 word2 word3是一个包含三个单词的列表,变量i依次等于word1word2word3,命令echo $i则会相应地执行三次。

    列表可以由通配符产生。

    1. for i in *.png; do
    2. ls -l $i
    3. done

    上面例子中,*.png会替换成当前目录中所有 PNG 图片文件,变量i会依次等于每一个文件。

    列表也可以通过子命令产生。

    1. #!/bin/bash
    2. count=0
    3. for i in $(cat ~/.bash_profile); do
    4. count=$((count + 1))
    5. echo "Word $count ($i) contains $(echo -n $i | wc -c) characters"
    6. done

    上面例子中,cat ~/.bash_profile命令会输出~/.bash_profile文件的内容,然后通过遍历每一个词,计算该文件一共包含多少个词,以及每个词有多少个字符。

    in list的部分可以省略,这时list默认等于脚本的所有参数$@。但是,为了可读性,最好还是不要省略,参考下面的例子。

    1. for filename; do
    2. echo "$filename"
    3. done
    4. # 等同于
    5. for filename in "$@" ; do
    6. echo "$filename"
    7. done

    在函数体中也是一样的,for...in循环省略in list的部分,则list默认等于函数的所有参数。

    for 循环

    for循环还支持 C 语言的循环语法。

    上面代码中,expression1用来初始化循环条件,expression2用来决定循环结束的条件,expression3在每次循环迭代的末尾执行,用于更新值。

    它等同于下面的while循环。

    1. (( expression1 ))
    2. while (( expression2 )); do
    3. commands
    4. (( expression3 ))
    5. done

    下面是一个例子。

    1. for (( i=0; i<5; i=i+1 )); do
    2. echo $i
    3. done

    上面代码中,初始化变量i的值为0,循环执行的条件是小于5。每次循环迭代结束时,i的值加1。

    for条件部分的三个语句,都可以省略。

    1. for ((;;))
    2. do
    3. read var
    4. if [ "$var" = "." ]; then
    5. break
    6. fi
    7. done

    上面脚本会反复读取命令行输入,直到用户输入了一个点(.)位为止,才会跳出循环。

    Bash 提供了两个内部命令breakcontinue,用来在循环内部跳出循环。

    break命令立即终止循环,程序继续执行循环块之后的语句,即不再执行剩下的循环。

    1. for number in 1 2 3 4 5 6
    2. do
    3. echo "number is $number"
    4. if [ "$number" = "3" ]; then
    5. break
    6. fi
    7. done

    上面例子只会打印3行结果。一旦变量$number等于3,就会跳出循环,不再继续执行。

    continue命令立即终止本轮循环,开始执行下一轮循环。

    1. #!/bin/bash
    2. while read -p "What file do you want to test?" filename
    3. do
    4. if [ ! -e "$filename" ]; then
    5. echo "The file does not exist."
    6. continue
    7. fi
    8. echo "You entered a valid file.."
    9. done

    上面例子中,只要用户输入的文件不存在,continue命令就会生效,直接进入下一轮循环(让用户重新输入文件名),不再执行后面的打印语句。

    select 结构

    select结构主要用来生成简单的菜单。它的语法与for...in循环基本一致。

    1. select name
    2. [in list]
    3. do
    4. commands
    5. done

    Bash 会对select依次进行下面的处理。

    1. select生成一个菜单,内容是列表list的每一项,并且每一项前面还有一个数字编号。
    2. Bash 提示用户选择一项,输入它的编号。
    3. 用户输入以后,Bash 会将该项的内容存在变量name,该项的编号存入环境变量REPLY。如果用户没有输入,就按回车键,Bash 会重新输出菜单,让用户选择。
    4. 执行命令体commands
    5. 执行结束后,回到第一步,重复这个过程。

    下面是一个例子。

    1. #!/bin/bash
    2. # select.sh
    3. select brand in Samsung Sony iphone symphony Walton
    4. do
    5. echo "You have chosen $brand"
    6. done

    执行上面的脚本,Bash 会输出一个品牌的列表,让用户选择。

    1. $ ./select.sh
    2. 1) Samsung
    3. 2) Sony
    4. 3) iphone
    5. 4) symphony
    6. 5) Walton
    7. #?

    如果用户没有输入编号,直接按回车键。Bash 就会重新输出一遍这个菜单,直到用户按下Ctrl + c,退出执行。

    select可以与case结合,针对不同项,执行不同的命令。