第29章:流程控制:while / until 循环
上一章中,我们开发了一款菜单驱动程序来制作各种类型的系统信息。程序能正常工作,但是还有个重大的可用性问题。它仅仅执行了单个选项之后就终止了。更糟糕的是,如果做出不合法的选择,程序就会报错并终止,没有给用户重新尝试的机会。如果能构建程序使其重复显示菜单并可以重复选择,直到用户自己选择退出程序为止,则会更友好。
本章中,我们将学习一个编程概念,循环(looping),使得部分程序可以重复。shell 提供了三种循环的复合命令。这里,我们将学两种,第三种将在后续章节中学习。
循环
日常生活中充满了重复的行为。每天工作、遛狗和切胡萝卜片,这些任务都涉及到重复一系列的步骤。让我们考虑切胡萝卜片吧。如果用伪代码表达这个行为,它可能看起来是这样的:
拿菜板
拿菜刀
把胡萝卜放在菜板上
举刀
把胡萝卜往前推
切片
如果整根胡萝卜都切成片了,就退出;否则回到第 4 步
从第 4 步到第 7 步组成了一个循环。循环中的行为会一直重复,直到满足「整根胡萝卜都切成片」这个条件为止。
while
bash
可以表达一个相似的概念。假设我们想要按序显示从 1 到 5 这五个数字。bash
脚本可以这样构建:
执行后,该脚本显示如下:
while
命令的句法如下:
while commands; do commands; done
和 if
一样,while
评估命令列表的退出状态。只要退出状态是 0
,它就执行循环内的命令。在上面的脚本中,创建了变量 count
,并分配了初值 1
。while
命令评估 [[ ]]
复合命令的退出状态。只要 [[ ]]
命令返回为零的退出状态,就执行在循环中的命令。在每一次循环的末尾,重复 [[ ]]
命令。在五次迭代循环之后,count
的之已经增加到了 6
,[[ ]]
命令不在返回为零的退出状态,循环终止了。程序就以循环之后的下一条命令继续。
我们可以用一个 while 循环来改进上一章的 read-menu
程序。
把菜单包括进一个 while
循环,就可以让程序在每次选择之后重复显示菜单。只要 REPLY
不等于 0
,则循环会继续,菜单会再次显示,以便给用户作出另一个选择的机会。每次行为之后,会执行 sleep
命令,使得程序暂停几秒钟,以便在清屏再次显示菜单之前能看到选择的结果。一旦 REPLY
等于 0
,指示 quit
选项,则循环终止,程序继续执行 done
之后的语句。
跳出循环
bash
提供了两个内建命令可以用来控制循环内的程序流。break
命令立即终止一个循环,程序控制用循环体的下一条语句重新开始。continue
命令导致循环内的其余命令被忽略,程序控制以下一次迭代的循环重新开始。来看一个整合了 break
和 continue
的 while-menu
程序:
这个版本的脚本中,我们用 true
命令提供一个退出状态给 while
,设置了一个无限循环(endless loop 即永远不会自行终止的循环)。由于 true
总是以 0
为退出状态,循环永远也不会终止。这是一个令人惊奇且常见的脚本技术。因为循环不会自行终止,就需要程序员提供某种方式在适当的时间退出循环。在这个脚本中,当选择 0
时,就用 break
命令退出循环。continue
命令被包含在其它脚本选项的末尾以提供更佳的执行效率。通过使用 continue
,当确定一个选项之后,脚本会忽略不需要的代码。例如,如果选择了 1
并确定之后,就没有理由去测试其它选项了。
until
until
命令很像 while
,只不过不是在遇到一个非零的退出状态才退出循环,而是相反。一个 until
循环会持续循环,直到接收到一个为 0
的退出状态。在 while-count
脚本中,只要 count
变量的值小于或等于 5
,就会持续循环。用 until
编写脚本,我们可以得到同样的结果。
将测试表达式变更为 $count -gt 5
,until
会在正确的时间终止循环。决定是否使用 while
或 until
循环,通常是选择一种可以最清晰的测试来编写。
用循环读取文件
while
和 until
可以处理标准输入。这使得文件可以用 while
和 until
循环来处理。在下面的例子中,我们将显示在前几章中出现过的 distros.txt
的内容:
要重定向一个文件到循环中,我们在 done
之后放置了重定向符。循环将使用 read
从重定向的文件中输入字段。read
命令会在读取每行后退出,其退出状态为 0
,直至到达文件末尾。到文件末尾,它会以一个非零的退出状态退出,从而终结循环。还可以将标准输入通过管道输入到循环中。
这里,我们取得 sort
命令的输出并显示其文本流。不过,重要的是要记住,因为管道会在 subshell 中执行循环,任何在循环中创建或分配的变量都会在循环终止时丢失。
总结
介绍了循环,和之前遇到的分支、子路径和序列,我们已经学习了编程中的流程控制的主要类型。bash
还有更多的窍门,但是它们都是在这些基本概念上的进一步完善罢了。
扩展阅读
Last updated
Was this helpful?