<>

3.4. 条件判断

虽然你可以通过上面的测试和&&、||控制操作符来完成一个大量的程序设计,不过Bash环境中还包含了更亲切的“if-then-else”和 case 语法结构。当你学会了这两种结构之后,你还会学到循环结构,这时你的知识结构才会真正拓展开来。

if-then-else语句

Bash环境下的if命令是一个复合的命令,它用来测试test语句或者是命令($?)的返回值,根据其真(0)或者假(非0)来执行不同的分支。虽然上面提到的test返回值非0即1,但命令还可能会返回其它的值。关于这点更多内容请到 LPI exam 102 prep: Shells, scripting, programming, and compiling 。

Bash环境下的if命令带一个then子句,这条子句包含一个命令序列,当测试或者是命令的返回值为0时执行。一个或多个可选的子句是elif,每条elif都会附带一个test测试和一条关联一组命令的then子句。最后else和一组命令也是可选的,当if语句中的测试或者是elif语句中的测试都不为真时会执行这组命令,在 if-then-else 结构的结尾用fi标示结束。

现在来使用一下刚刚学到的吧,你可以创建一个简单的计算器来计算一下算术表达式,Example 3.9, “用 if-then-else 来计算表达式”.

Example 3.9. 用 if-then-else 来计算表达式

[user@domain ~]$ function mycalc ()
> {
>   local x
>   if [ $# -lt 1 ]; then
>     echo "This function evaluates arithmetic for you if you give it some"
>   elif (( $* )); then
>     let x="$*"
>     echo "$* = $x"
>   else
>     echo "$* = 0 or is not an arithmetic expression"
>   fi
> }
[user@domain ~]$ mycalc 3 + 4
3 + 4 = 7
[user@domain ~]$ mycalc 3 + 4**3
3 + 4**3 = 67
[user@domain ~]$ mycalc 3 + (4**3 /2)
-<application>Bash</application>: syntax error near unexpected token `('
[user@domain ~]$ mycalc 3 + "(4**3 /2)"
3 + (4**3 /2) = 35
[user@domain ~]$ mycalc xyz
xyz = 0 or is not an arithmetic expression
[user@domain ~]$ mycalc xyz + 3 + "(4**3 /2)" + abc
xyz + 3 + (4**3 /2) + abc = 35

这个计算器用local那句声明了一个本地变量x,它只在mycalc函数的范围内有效。let函数可以有多个选项,像declare函数一样,选项与函数的作用也是密切相关联。更多信息请查看Bash的 man 手册,或者通过help let获得。

Example 3.9, “用 if-then-else 来计算表达式”中看到的,你需要确认如果你的表达式用到了 shell 的元字符像( 、 ) 、 * 、 ><,它们应该被正确地转义。虽然如此,你有了这个按照 shell 的方式来计算算术的相当方便小巧的计算器。

你可能已经注意到了Example 3.9, “用 if-then-else 来计算表达式”中的else子句以及最后两个例子。正如你看到的,给计算器传递xyz它并不会产生错误,但是xyz会被计算成 0 。这个函数并没有那么智能能指出最后的那个例子中用了字符值,并提醒用户。你可以用一个字符串的匹配测试[[ ! ("$*" == *[a-zA-Z]* ]](或者根据你自己设置适当的形式)来排除表达式中包含拼音字母的情况。但是这会阻止十六进制表示法的使用,因为你使用了0x0f来表达十六进制形式的 15 。实际上,shell 环境是允许基数最大到 64 (用base#value表示),这样你可以合理地使用任意拼音字母,包括 _ 和 @ 作为你的输入。用 0 打头的八进制和用 0x 或 0X 打头的十六进制最常用的进制表达法。Example 3.10, “不同基数的运算”列举了一些例子。

Example 3.10. 不同基数的运算

[user@domain ~]$ mycalc 015
015 = 13
[user@domain ~]$ mycalc 0xff
0xff = 255
[user@domain ~]$ mycalc 29#37
29#37 = 94
[user@domain ~]$ mycalc 64#1az
64#1az = 4771
[user@domain ~]$ mycalc 64#1azA
64#1azA = 305380
[user@domain ~]$ mycalc 64#1azA_@
64#1azA_@ = 1250840574
[user@domain ~]$ mycalc 64#1az*64**3 + 64#A_@
64#1az*64**3 + 64#A_@ = 1250840574

这些附加的输入已经走出了这篇文章的范围,用你的这个计算器时请谨慎使用。

elif语句非常方便,它帮助你在写脚本时简单地实现的缩进。当你看到Example 3.11, “打印 mycalc”中通过type命令查看mycalc函数的内容时你可能会惊讶。

Example 3.11. 打印 mycalc

[user@domain ~]$ type mycalc
mycalc is a function
mycalc ()
{
    local x;
    if [ $# -lt 1 ]; then
        echo "This function evaluates arithmetic for you if you give it some";
    else
        if (( $* )); then
            let x="$*";
            echo "$* = $x";
        else
            echo "$* = 0 or is not an arithmetic expression";
        fi;
    fi
}

当然,你可以像Example 3.12, “直接在 shell 环境中通过(( ))和echo命令运算”中一样通过$(( expression ))echo命令仅仅利用 shell 做算术。那种方式你不会学会任何与函数有关的东西,但提示你的是,在(( expression ))或者是[[ expression ]]中, shell 不会翻译元字符,像 * 等等。

Example 3.12. 直接在 shell 环境中通过(( ))echo命令运算

[user@domain ~]$  echo $((3 + (4**3 /2)))
35