Bash Shell条件分支

你想要检查参数数量是否正确并执行相应的操作。这得用到条件分支

解决方案

bash 中的 if 语句表面上和其他语言中的差不多。

if [ $# -lt 3 ]
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
fi

或者:

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
fi

以下是一个带有 elif(bash 中的 else-if)和 else 子句的完整 if 语句。

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
elif (( $# > 3 ))
then
    printf "%b" "Error. Too many arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 2
else
    printf "%b" "Argument count correct. Proceeding...\n"
fi

甚至可以写成:

[ $result = 1 ] \
  && { echo "Result is 1; excellent." ; exit 0;   } \
  || { echo "Uh-oh, ummm, RUN AWAY! " ; exit 120; }

讨论

我们有两件事需要讨论:if 语句的基本结构和 if 表达式的不同语法(括号或方括号,运算符或选项)。前者也许有助于解释后者。按照 bash 手册页中的描述,if 语句的一般形式如下所示。

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

[] 用于划分语句中的可选部分(例如,有些 if 语句中就没有 else 子句)。我们先来看看不带任何可选部分的 if 语句。

最简单的 if 语句形式如下所示。

if list; then list; fi

在 bash 中,和换行符一样,分号的作用也是结束某个语句。我们可以用分号将解决方案部分中的示例塞进更少的行中,但使用换行符的可读性更好。
then list 的存在看起来是有意义的,其中的语句在 if 条件为真的情况下执行(我们也可以从其他编程语言中猜测出来)。但是,if list 算是怎么回事?难道不应该是 if expression 吗?

没错,但这是 shell,一个命令处理器。它的主要任务就是执行命令。因此,if 后面的 list 就是放置命令列表的地方。你可能会问,决定分支走向(then 子句或 else 子句)的是什么呢?答案是 list 中最后一个命令的返回值。(你可能还记得,返回值可以从变量 $? 中获取。)

我们通过一个有点奇怪的示例来说明这一点。

$ cat trythis.sh
if ls; pwd; cd $1;
then
    echo success
else
    echo failed
fi
pwd

$ bash ./trythis.sh /tmp
...
$ bash ./trythis.sh /nonexistent
...
$

在这个奇怪的脚本中,shell 会在选择分支前执行 3 个命令(ls、pwd、cd),其中 cd 命令的参数是调用该脚本时所提供的第一个命令行参数。如果没有提供参数,那就只执行 cd,返回到主目录中。

结果会是怎样?你可以自己试试。最终是显示“success”还是“failed”,取决于 cd 命令是否执行成功。在示例中,cd 是 if 语句命令列表中的最后一个命令。如果 cd 执行失败,就转到 else 子句;但如果执行成功,则选择 then 子句。

如果命令书写正确,同时执行过程中没有出现错误,那么返回值为 0。如果有错误(如参数有问题、I/O 错误、找不到指定文件),则返回非 0 值(不同的错误种类通常对应不同的值)。

这就是为什么 shell 脚本编写人员和 C(以及其他语言)程序员要确保退出脚本和程序时返回有意义的值,这一点很重要。有些 if 语句可能依赖于此。

那么我们该如何从这个奇怪的 if 构造中找出与真实 if 语句(经常在程序中看到的那种)相似的地方?这则实例开头部分的那些示例是怎么回事?毕竟它们看起来并不像是语句列表。

我们来看看以下这段代码。

if test $# -lt 3
then
    echo try again.
fi

就算不是命令列表,但有没有从中看出起码类似于单个 shell 命令(内建命令 test 接受参数并比较参数值)的东西?如果比较结果为真,那么 test 命令会返回 0,否则返回 1。你可以自己动手在命令行上尝试一下这个命令,然后用 echo $? 查看返回值。

我们给出的第一个示例中开头的 if [ $# -lt 3 ] 看起来很像 test 命令。这是因为 [ 其实只是相同命令的不同名称而已。(出于可读性和美观方面的考虑,调用 [ 时还要求将 ] 作为最后一个参数。)因此,对于该语法,if 语句中的表达式其实就是一个只包含单个命令(test 命令)的列表。

 在早期的 Unix 中,test 是一个独立的可执行文件,[ 只是指向该文件的链接。现在两者仍以可执行文件的形式存在,但 bash 也将它们实现为内建命令。
 

两者的可执行文件分别位于 /bin/test/bin/[。将其实现为内建命令是为了提高执行效率。

那么 if (( $# < 3 )) 又是什么意思?双括号是复合命令的一种。因为它会对其中的算术表达式求值,所以能在 if 语句中派上用场。这是一处比较新的 bash 改进 ,专门用于有 if 语句的场合。

可用于 if 语句的这两种语法之间的重要区别在于测试的表达方式及其能够测试的对象种类。双括号仅限于算术表达式,方括号还可以测试文件特性,但后者的算术测试语法远不如前者方便,尤其是用括号将表达式划分成若干子表达式时(在方括号中,需要给括号加上引号或将其转义)。

酷客网相关文章:

赞(0)

评论 抢沙发

评论前必须登录!