3 第18章 控制流结构
3.1 退出状态
在书写正确脚本前,大概讲一下退出状态。任何命令进行时都将返回一个退出状态。如
果要观察其退出状态,使用最后状态命令:
$ echo $?
主要有4种退出状态。前面已经讲到了两种,即最后命令退出状态$ ?和控制次序命令( $ $、
| |)。其余两种是处理s h e l l脚本或s h e l l退出及相应退出状态或函数返回码。在第1 9章讲到函数时,也将提到其返回码。
要退出当前进程,s h e l l提供命令e x i t,一般格式为:
exit n,其中,n为一数字。
如果只在命令提示符下键入exit,假定没有在当前状态创建另一个shell,将退出当前s h e l l。
如果在脚本中键入e x i t,s h e l l将试图(通常是这样)返回上一个命令返回值。有许多退出脚本值,但其中相对于脚本和一般系统命令最重要的有两种,即:
退出状态0 退出成功,无错误。
退出状态1 退出失败,某处有错误。
可以在s h e l l脚本中加入自己的退出状态(它将退出脚本)。本书鼓励这样做,因为另一个
s h e l l脚本或返回函数可能要从s h e l l脚本中抽取退出脚本。另外,相信加入脚本本身的退出脚本值是一种好的编程习惯。
如果愿意,用户可以在一个用户输入错误后或一个不可覆盖错误后或正常地处理结束后
退出脚本。
注意从现在起,本书所有脚本都将加入注释行。注释行将解释脚本具体含义,帮助用户
理解脚本。可以在任何地方加入注释行,因为其本身被解释器忽略。注释行应以#开头。
3.2 流控制
i f、t h e n、e l s e语句提供条件测试。测试可以基于各种条件。例如文件的权限、长度、数
值或字符串的比较。这些测试返回值或者为真( 0),或者为假( 1)。基于此结果,可以进行
相关操作。在讲到条件测试时已经涉及了一些测试语法。
c a s e语句允许匹配模式、单词或值。一旦模式或值匹配,就可以基于这个匹配条件作其他
声明。
3.3 循环
循环或跳转是一系列命令的重复执行过程,本书提到了3种循环语句:
for 循环每次处理依次列表内信息,直至循环耗尽。
Until 循环此循环语句不常使用, u n t i l循环直至条件为真。条件部分在循环末尾部分。
While 循环w h i l e循环当条件为真时,循环执行,条件部分在循环头。
流控制语句的任何循环均可嵌套使用,例如可以在一个f o r循环中嵌入另一个f o r循环。
现在开始讲解循环和控制流,并举一些脚本实例。
从现在起,脚本中echo语句使用LINUX或B S D版本,也就是说使用echo方法echo -e -n,
意即从e c h o结尾中下一行执行命令。应用于U N I X(系统V和B S D)的统一的e c h o命令参阅1 9章s h e l l函数。
3.4 if then else语句
i f语句测试条件,测试条件返回真( 0)或假(1)后,可相应执行一系列语句。i f语句结
构对错误检查非常有用。其格式为:
if 条件1
then 命令1
elif 条件2
then 命令2
else 命令3
f i
让我们来具体讲解i f语句的各部分功能。
If 条件1 如果条件1为真
Then 那么
命令1 执行命令1
elif 条件2 如果条件1不成立
then 那么
命令2 执行命令2
else 如果条件1,2均不成立
命令3 那么执行命令3
fi 完成
i f语句必须以单词f i终止。在i f语句中漏写f i是最一般的错误。我自己有时也是这样。
e l i f和e l s e为可选项,如果语句中没有否则部分,那么就不需要e l i f和e l s e部分。I f语句可以
有许多e l i f部分。最常用的i f语句是if then fi结构。
3.5 简单的if语句
最普通的i f语句是:
i f条件
then 命令
f i
使用i f语句时,必须将t h e n部分放在新行,否则会产生错误。如果要不分行,必须使用命
令分隔符。本书其余部分将采取这种形式。现在简单i f语句变为:
if 条件;t h e n
命令
f i
注意,语句可以不这样缩排,但建议这样做,因为可以增强脚本的清晰程度。在条件流
下采取命令操作更方便。
3.6 case语句
c a s e语句为多选择语句。可以用c a s e语句匹配一个值与一个模式,如果匹配成功,执行相
匹配的命令。c a s e语句格式如下:
case 值i n
模式1 }
命令1
. . .
; ;
模式2)
命令2
. . .
;;
e s a c
c a s e工作方式如上所示。取值后面必须为单词i n,每一模式必须以右括号结束。取值可以
为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续
其他模式。如果无一匹配模式,使用星号*捕获该值,再接受其他输入。
模式部分可能包括元字符,与在命令行文件扩展名例子中使用过的匹配模式类型相同,
即:
* 任意字符。
?任意单字符。
[..] 类或范围中任意字符。
3.7 对匹配模式使用|
使用c a s e时,也可以指定“|”符号作为或命令,例如v t 1 0 0 | v t 1 0 2匹配模式v t 1 0 0或v t 1 0 2。
3.8 for循环
f o r循环一般格式为:
for 变量名 i n 列表
d o
命令1
命令2⋯
d o n e
当变量值在列表里, f o r循环即执行一次所有命令,使用变量名访问列表中取值。命令可
为任何有效的s h e l l命令和语句。变量名为任何单词。I n列表用法是可选的,如果不用它, f o r
循环使用命令行的位置参数。
i n列表可以包含替换、字符串和文件名,下面看一些例子。
3.9 对for循环使用参数
在f o r循环中省去i n列表选项时,它将接受命令行位置参数作为参数。实际上即指明:
for params in"$@"
或
for params in"$*"
下面的例子不使用i n列表选项, f o r循环查看特定参数$ @或$ *,以从命令行中取得参数。
3.10 for循环嵌入
嵌入循环可以将一个f o r循环嵌在另一个f o r循环内:
for 变量名1 in列表1
d o
for 变量名2 in 列表2
d o
命令1
. . .
d o n e
d o n e
3.11 until循环
u n t i l循环执行一系列命令直至条件为真时停止。u n t i l循环与w h i l e循环在处理方式上刚好相反。一般w h i l e循环优于u n t i l循环,但在某些时候—也只是极少数情况下, u n t i l循环更加有用。
u n t i l循环格式为:
until 条件
命令1
. . .
d o n e
条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次—请注意这一
点。
3.12 while循环
w h i l e循环用于不断执行一系列命令,也用于从输入文件中读取数据,其格式为:
while 命令
d o
命令1
命令2
. . .
d o n e
虽然通常只使用一个命令,但在w h i l e和d o之间可以放几个命令。命令通常用作测试条
件。
只有当命令的退出状态为0时,d o和d o n e之间命令才被执行,如果退出状态不是0,则循
环终止。
命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。
还有w h i l e循环用到了空命令(:),这是一个死循环,因为n u l l永远返回真。尝试读至文件结尾将返回错误,那时脚本也终止执行。
3.13 break
b r e a k命令允许跳出循环。b r e a k通常在进行一些处理后退出循环或c a s e语句。如果是在一个嵌入循环里,可以指定跳出的循环个数。例如如果在两层循环内,用break 2刚好跳出整个循环。
3.14 continue
c o n t i n u e命令类似于b r e a k命令,只有一点重要差别,它不会跳出循环,只是跳过这个循环步。