每一种条件语句的基础都是判断什么是真什么是假。是否了解其工作原理将决定您编写的是质量一般的脚本还是您将引以为荣的脚本。
Shell 脚本的能力时常被低估,但实际上其能力的发挥受制于脚本撰写者的能力。您了解得越多,您就越能像变戏法似地撰写一个文件来使任务自动化和简化您的管理工作。
在 shell 脚本中进行的每一种操作(除最简单的命令编组之外)都需要检查条件。所有的 shell 脚本“逻辑” — 广义意义下的“逻辑” — 通常都可以分为以下三大类:
if {condition exists} then ...while {condition exists} do ...until {condition exists} do ...
无论随后的操作是什么,这些基于逻辑的命令都依靠判断一种条件是否真实存在来决定后续的操作。test命令是使得在每一种情况下都能够确定要判断的条件是否存在的实用工具。因此,彻底了解这个命令对于撰写成功的 shell 脚本至关重要。
工作原理
test 命令最短的定义可能是评估一个表达式;如果条件为真,则返回一个 0 值。如果表达式不为真,则返回一个大于 0 的值 — 也可以将其称为假值。检查最后所执行命令的状态的最简便方法是使用 $? 值。出于演示的目的,本文中的例子全部使用了这个参数。
test命令期望在命令行中找到一个参数,当 shell 没有为变量赋值时,则将该变量视为空。这意味着在处理脚本时,一旦脚本寻找的参数不存在,则test将报告该错误。
当试图保护脚本时,您可以通过将所有参数包含在双引号中来解决这个问题。然后 shell 将变量展开,如果变量没有值,那么将传递一个空值给test。另一种方法是在脚本内增加一个额外检查过程来判断是否设置了命令行参数。如果没有设置命令行参数,那么脚本会告诉用户缺少参数,然后退出。我们会通过一些例子来更具体地说明所有这些内容。
test和[命令
虽然 Linux 和 UNIX 的每个版本中都包含test命令,但该命令有一个更常用的别名 — 左方括号:[。test及其别名通常都可以在 /usr/bin 或 /bin (取决于操作系统版本和供应商)中找到。
当您使用左方括号而非test时,其后必须始终跟着一个空格、要评估的条件、一个空格和右方括号。右方括号不是任何东西的别名,而是表示所需评估参数的结束。条件两边的空格是必需的,这表示要调用test,以区别于同样经常使用方括号的字符/模式匹配操作。
test和[的语法如下:
test expression[ expression ]
在这两种情况下,test都评估一个表达式,然后返回真或假。如果它和if、while或until命令结合使用,则您可以对程序流进行广泛的控制。不过,您无需将test命令与任何其它结构一起使用;您可以从命令行直接运行它来检查几乎任何东西的状态。
因为它们彼此互为别名,所以使用test或[均需要一个表达式。表达式一般是文本、数字或文件和目录属性的比较,并且可以包含变量、常量和运算符。运算符可以是字符串运算符、整数运算符、文件运算符或布尔运算符 — 我们将在以下各部分依次介绍每一种运算符。
test文件运算符
利用这些运算符,您可以在程序中根据对文件类型的评估结果执行不同的操作:
-bfile | 如果文件为一个块特殊文件,则为真 |
-cfile | 如果文件为一个字符特殊文件,则为真 |
-dfile | 如果文件为一个目录,则为真 |
-efile | 如果文件存在,则为真 |
-ffile | 如果文件为一个普通文件,则为真 |
-gfile | 如果设置了文件的 SGID 位,则为真 |
-Gfile | 如果文件存在且归该组所有,则为真 |
-kfile | 如果设置了文件的粘着位,则为真 |
-Ofile | 如果文件存在并且归该用户所有,则为真 |
-pfile | 如果文件为一个命名管道,则为真 |
-rfile | 如果文件可读,则为真 |
-sfile | 如果文件的长度不为零,则为真 |
-Sfile | 如果文件为一个套接字特殊文件,则为真 |
-tfd | 如果 fd 是一个与终端相连的打开的文件描述符(fd 默认为 1),则为真 |
-ufile | 如果设置了文件的 SUID 位,则为真 |
-wfile | 如果文件可写,则为真 |
-xfile | 如果文件可执行,则为真 |
以下示例显示了此简单操作的运行情况:
$ ls -ltotal 33drwxr-xr-w 2 root root 1024 Dec 5 05:05 LST-rw-rw-rw- 1 emmett users 27360 Feb 6 07:30 evan-rwsrwsrwx 1 root root 152 Feb 6 07:32 hannahdrwxr-xr-x 2 emmett users 1024 Feb 6 07:31 karen-rw------- 1 emmett users 152 Feb 6 07:29 kristin-rw-r--r-- 1 emmett users 152 Feb 6 07:29 spencer$$ test -r evan$ echo $?0$ test -r walter$ echo $?1$
由于第一次评估为真 — 文件存在且可读 — 返回值为真,或 0。由于第二次评估的文件不存在,该值为假,返回值不为零。将值指定为零或非零很重要,因为在失败时不会始终返回 1(虽然这是通常返回的值),可能返回一个非零值。