Bash 有两种循环方式:
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
下面是一种你经常见到的反模式:遍历cat的输出。
for line in $(cat some.file); do
do_something_with "$line"
done
这有两个错误。
for循环遍历的是文件里的词,而不是行。正如我们在引号概念中学到的,分词可以用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。
这会临时关闭分词,从而保留输入行首尾的空白字符。
untiluntil结构在某个条件为 false 时重复执行一系列命令。
循环会一直重复,_直到_该条件变为 true。
until CONDITION_COMMANDS; do COMMANDS; done
很少使用until。
更常见的是使用“while not”循环。
while ! CONDITION_COMANDS; do ...
有时你想无限循环下去。 下面有两种做法。
条件总是返回成功退出状态的while循环
while true; do ...
表达式为空的算术for循环
for ((;;)); do ...
没有显式的 do-while 结构,但你可以达到同样的效果:
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done