循环

循环 属于 Bash

{other: "%{count} 个练习"}

关于 循环

Bash 有两种循环方式:

  • 对_列表中的每一项_重复执行一些命令,
  • _在某个条件为 true(或 false)时_重复执行一些命令。

for循环

要遍历一个列表中的各项,我们使用for循环。

for varname in words; do COMMANDS; done

words会经过分词和文件名扩展展开(我们在引号概念中学过)。 每个词会依次赋值给varname,然后执行 COMMANDS。

下面这些例子展示了for循环在什么时候有用

  • 对一组文件执行一些命令。

    # source all the bash library files in the current directory
    for file in ./*.bash; do
        source "$file"
    done
    
  • 对脚本或函数的每个形参执行一些命令。

    for arg in "$@"; do
        echo "argument: ${arg}"
    done
    
  • 对某条命令输出中每个以空白分隔的词执行一些命令。

    for i in $(seq 10); do
        echo "${i} squared is $((i * i))"
    done
    

    稍后我们会看到关于这种写法的几点警告。

算术for循环

Bash 确实有算术循环。 对其他编程语言来说,这会有些眼熟。

for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done

Bash 中的双括号表示算术上下文(我们会在后面的概念里进一步了解 Bash 算术)。 上面那个使用seq的例子可以这样写

for ((i = 1; i <= 10; i++)); do
    echo "${i} squared is $((i * i))"
done

何时不该用for

不要用for读取行。

下面是一种你经常见到的反模式:遍历cat的输出。

for line in $(cat some.file); do 
    do_something_with "$line"
done

这有两个错误。

  1. 命令替换没有加引号,因此会受到分词的影响。 默认情况下,分词按_空白字符_来拆分,而不只是按换行符拆分。 这个for循环遍历的是文件里的词,而不是行。
  2. 命令替换没有加引号,因此会受到文件名扩展的影响。 文件里的每个词都会被当作通配模式来匹配。

正如我们在引号概念中学到的,分词可以用IFS变量来控制,文件名扩展也可以关闭。 但这种做法往往很脆弱。 要遍历文件的行,for是错误的做法。 读取文件的地道方式是用while循环。

while循环

使用while,_在某个条件为 true 时_重复执行一系列命令。

while CONDITION_COMMANDS; do COMMANDS; done

和if一样(我们在条件概念中学过),CONDITION_COMMANDS 没有特殊的语法。 命令列表的退出状态会决定“true”还是“false”。

控制循环

break命令会跳出循环。 控制权从循环的done终止符之后的那条命令继续。

continue命令会跳到循环的下一次迭代。

读取文件的行

如前所述,while循环是读取文件的地道方式。

while IFS= read -r line; do
    do_something_with "$line"
done < some.file
  • 文件的内容通过<重定向作为输入提供给循环。

  • 只要能从中读取完整的一行,read命令就返回“true”。 当输入被读完,或者最后一行末尾没有换行符时,read返回“false”。

    • _真正_地道地读取文件各行的方法,即使最后一行末尾没有换行符,是

      while IFS= read -r line || [[ -n "$line" ]]; do ...
      
  • -r选项告诉read不要替换反斜杠序列:反斜杠只是一个普通字符。

  • IFS=只在read命令执行期间把空字符串赋给 IFS。 这会临时关闭分词,从而保留输入行首尾的空白字符。

until

until结构在某个条件为 false 时重复执行一系列命令。 循环会一直重复,_直到_该条件变为 true。

until CONDITION_COMMANDS; do COMMANDS; done

很少使用until。 更常见的是使用“while not”循环。

while ! CONDITION_COMANDS; do ...

无限循环

有时你想无限循环下去。 下面有两种做法。

  1. 条件总是返回成功退出状态的while循环

    while true; do ...
    
  2. 表达式为空的算术for循环

    for ((;;)); do ...
    

Do-While

没有显式的 do-while 结构,但你可以达到同样的效果:

while true; do
    COMMANDS

    if END_CONDITION; then
        break
    fi
done
通过 GitHub 编辑 该链接会在新窗口或标签页中打开