test 命令详解

来源:互联网 发布:男士用什么护肤品知乎 编辑:程序博客网 时间:2024/05/15 02:57
每一种条件语句的基础都是判断什么是真什么是假。是否了解其工作原理将决定您编写的是质量一般的脚本还是您将引以为荣的脚本。
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 文档运算符
利用这些运算符,您能够在程式中根据对文档类型的评估结果执行不同的操作:
-b file 假如文档为一个块特别文档,则为真
-c file 假如文档为一个字符特别文档,则为真
-d file 假如文档为一个目录,则为真
-e file 假如文档存在,则为真
-f file 假如文档为一个普通文档,则为真
-g file 假如配置了文档的 SGID 位,则为真
-G file 假如文档存在且归该组任何,则为真
-k file 假如配置了文档的粘着位,则为真
-O file 假如文档存在并且归该用户任何,则为真
-p file 假如文档为一个命名管道,则为真
-r file 假如文档可读,则为真
-s file 假如文档的长度不为零,则为真
-S file 假如文档为一个套接字特别文档,则为真
-t fd 假如 fd 是个和终端相连的打开的文档描述符(fd 默认为 1),则为真
-u file 假如配置了文档的 SUID 位,则为真
-w file 假如文档可写,则为真
-x file 假如文档可执行,则为真
以下示例显示了此简单操作的运行情况:
$ ls -l
total 33
drwxr-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 hannah
drwxr-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(虽然这是通常返回的值),可能返回一个非零值。
正如开头所提到的,除了使用 test 外,您还能够用方括号 [ ] 将命令括住来向 shell 发出同样的命令 — 如下所示:
$ [ -w evan ]
$ echo $?
0
$ [ -x evan ]
$ echo $?
1
$
同样,第一个表达式为真,第二个表达式为假 — 正如返回值所指示的那样。您还能够使用以下命令将两个文档彼此进行比较:
file1 -ef file2 测试以判断两个文档是否和同一个设备相连,是否拥有相同的 inode 编号
file1 -nt file2 测试以判断第一个文档是否比第二个文档更新(由修改日期决定)
file1 -ot file2 测试以判断第一个文档是否比第二个文档更旧
以下示例显示了使用这些运算符比较文档的结果:
$ [ evan -nt spencer ]
$ echo $?
0
$ [ karen -ot spencer ]
$ echo $?
1
$
名为 evan 的文档比名为 spencer 的文档更新,因而评估为真。类似地,名为 karen 的文档比名为 spencer 的文档更新,因此该评估为假。
字符串比较运算符
如标题所示,这组函数比较字符串的值。您能够检查他们是否存在、是否相同或是否不同。
String 测试以判断字符串是否不为空
-n string 测试以判断字符串是否不为空;字符串必须为 test 所识别
-z string 测试以判断字符串是否为空;字符串必须为 test 所识别
string1 = string2 测试以判断 string1 是否和 string2 相同
string1 != string2 测试以判断 string1 是否和 string2 不同
对任何变量进行的最有用的测试之一是判断他的值是否不为空,能够简单地将其放在 test 命令行中执行这种测试,如下例所示:
$ test "$variable"
强烈建议进行此种测试时用双引号将变量括住,以让 shell 识别变量(即使变量为空)。默认情况下执行的基本字符串评估和 -n 测试从功能上讲是相同的,如以下示例所示:
#example1
if test -n "$1"
then
echo "$1"
fi
执行以上例子中的代码将根据 $1 是否存在给出以下结果:
$ example1 friday
friday
$
$ example1
$
假如将代码更改为以下形式,则结果将相同:
#example2
if test "$1"
then
echo "$1"
fi
如下所示:
$ example2 friday
friday
$
$ example2
$
任何这些表明,通常无需 -n,他代表默认操作。
要从一个不同的角度来查看各种可能性,您能够用另一个选项来替换 -n,并检查该值是否为空(相对于非空)。这能够用 -z 选项来实现,代码为:
#example3
if test -z "$1"
then
echo "no values were specified"
fi
运行如下:
$ example3
no values were specified
$ example3 friday
$
假如在没有命令行参数的情况下运行该程式,而表达式评估为真,那么将执行程式块中的文本。假如在命令行中有值,则脚本退出,不执行任何操作。将评估操作放在脚本的开头很有用,这能够在可能产生错误的进一步处理之前预先检查变量值。
其余的字符串运算符对两个变量/字符串之间的精确匹配或其中的差异(您也能够称之为等价性和“不等价性”)进行评估。第一个例子对匹配进行测试:
$ env
LOGNAME=emmett
PAGER=less
SHELL=/bin/bash
TERM=linux
$
$ [ "$LOGNAME" = "emmett" ]
$ echo $?
0
$
$ [ "$LOGNAME" = "kristin" ]
$ echo $?
1
$
或,该评估能够以脚本的形式用于决定是否运行脚本:
#example4
if [ "$LOGNAME" = "emmett" ]
then
echo "processing beginning"
else
echo "incorrect user"
fi
这种方法能够用来寻找任意的值(如终端类型或 shell 类型),在允许脚本运行之前这些值必须匹配。请注意,= 或 != 运算符的优先级高于其他大多数可指定选项,且需要必须伴有表达式。因此,除了比较字符串的选项之外,= 或 != 都不能和检查某种东西(如可读文档、可执行文档或目录)的存在性的选项一起使用。
整数比较运算符
正如字符串比较运算符验证字符串相等或不同相同,整数比较运算符对数字执行相同的功能。假如变量的值匹配则表达式测试为真,假如不匹配,则为假。整数比较运算符不处理字符串(正如字符串运算符不处理数字相同):
int1 -eq int2 假如 int1 等于 int2,则为真
int1 -ge int2 假如 int1 大于或等于 int2,则为真
int1 -gt int2 假如 int1 大于 int2,则为真
int1 -le int2 假如 int1 小于或等于 int2,则为真
int1 -lt int2 假如 int1 小于 int2,则为真
int1 -ne int2 假如 int1 不等于 int2,则为真
以下示例显示了一个代码段,其中在命令行中给出的值必须等于 7:
#example5
if [ $1 -eq 7 ]
then
echo "You've entered the magic number."
else
echo "You've entered the wrong number."
fi
运行中:
$ example5 6
You've entered the wrong number.
$
$ example5 7
You've entered the magic number.
$
和字符串相同,比较的值能够是在脚本外为变量赋的值,而不必总是在命令行中提供。以下示例演示了实现这一点的一种方法:
#example6
if [ $1 -gt $number ]
then
echo "Sorry, but $1 is too high."
else
echo "$1 will work."
fi
$ set number=7
$ export number
$ example6 8
Sorry, but 8 is too high.
$ example6 7
7 will work.
$
整数比较运算符最好的用途之一是评估指定的命令行变量的数目,并判断他是否符合所需要的标准。例如,假如某个特定的命令只能在有三个或更少变量的情况下运行,
#example7 - display variables, up to three
if [ "$#" -gt 3 ]
then
echo "You have given too many variables."
exit $#
fi
只要指定三个或更少的变量,该示例脚本将正常运行(并返回值 0)。假如指定了三个以上的变量,则将显示错误消息,且例程将退出 — 同时返回和命令行中给定的变量数相等的退出代码。
对这个过程进行修改能够用来在允许运行报表之前判断当天是否是本月的最后几天:
#example8 - to see if it is near the end of the month#
set `date` # use backward quotes
if [ "$3" -ge 21 ]
then
echo "It is close enough to the end of the month to proceed"
else
echo "This report cannot be run until after the 21st of the month"
exit $3
fi
在这个例子中,配置了六个变量(通过空格彼此分开):
$1 = Fri
$2 = Feb
$3 = 6
$4 = 08:56:30
$5 = EST
$6 = 2004
这些值能够在脚本中使用,就像他们是在命令行中输入的相同。请注意,退出命令再次返回一个值 — 在这种情况下,返回的值是从 $3 的值中得到的日期。这一技巧在故障诊断时会很有用 — 假如您认为脚本应该运行而没有运行,那么请查看 $? 的值。
一种类似的想法可能是撰写一个只在每个月的第三个星期三运行的脚本。第三个星期三一定在该月的 15 日到 21 日之间。使用 cron,您能够调用脚本在 15 日到 21 日之间每天的一个指定时间运行,然后使用脚本的第一行检查 $1(在配置日期之后)的值是否为 Thu。假如为 Thu,那么执行剩下的脚本,假如不是,则退出。
而另一个想法可能是,只允许脚本在超过 6:00 p.m. (18:00),任何用户都回家之后运行。只要撰写脚本,使其在值低于 18 时退出,并通过使用以下命令来获取时间(将其设为 $1)
set `date +%H`
布尔运算符
布尔运算符在几乎每种语言中的工作方式都相同 — 包括 shell 脚本。在 nutshell 中,他们检查多个条件为真或为假,或针对假的条件而不是真的条件采取操作。和 test 搭配使用的运算符有
! expr 假如表达式评估为假,则为真
expr1 -a expr2 假如 expr1 和 expr2 评估为真,则为真
expr1 -o expr2 假如 expr1 或 expr2 评估为真,则为真
能够用 != 运算符代替 = 进行字符串评估。这是最简单的布尔运算符之一,对 test 的正常结果取非。
其余两个运算符中的第一个是 -a(即 AND)运算符。要使测试最终为真,两个表达式都必须评估为真。假如任何一个评估为假,则整个测试将评估为假。例如,
$ env
HOME=/
LOGNAME=emmett
MAIL=/usr/mail/emmett
PATH=:/bin:/usr/bin:/usr/lbin
TERM=linux
TZ=EST5:0EDT
$
$ [ "$LOGNAME" = "emmett" -a "$TERM" = "linux" ]
$ echo $?
0
$
$ [ "LOGNAME" = "karen" -a "$TERM" = "linux" ]
$ echo $?
1
$
在第一个评估中,两个条件都测试为真(在一个 linux 终端上登录的是 emmett),因此整个评估为真。在第二个评估中,终端检查正确但用户不正确,因此整个评估为假。
简而言之,AND 运算符能够确保代码只在两个条件都满足时才执行。相反,只要任何一个表达式测试为真,OR (-o) 运算符即为真。我们来修改先前的例子,并将其放到一个脚本中来说明这一点:
#example9
if [ "$LOGNAME" = "emmett" -o "$TERM" = "linux" ]
then
echo "Ready to begin."
else
echo "Incorrect user and terminal."
fi
$ env
HOME=/
LOGNAME=emmett
MAIL=/usr/mail/emmett
PATH=:/bin:/usr/bin:/usr/lbin
TERM=linux
TZ=EST5:0EDT
$ example9
Ready to begin.
$
$ LOGNAME=karen
$ example9
Ready to begin.
$
在脚本第一次运行时,评估判断用户是否等于 emmett。假如发现用户等于 emmett,则脚本转至 echo 语句,并跳过其余的检查。他从不检查终端是否等于 linux,因为他只需要找到一条为真的语句就能够使整个运算为真。在脚本第二次运行时,他判断用户不是 emmett,因此他将检查并发现终端确实是 linux。由于一个条件为真,脚本现在转至 echo 命令。为了引出第二条消息,两个条件都必须为假。
在先前确定时间是否为月末的例子中,能够执行类似的检查来防止用户试图在周末运行脚本:
#example10 - Do not let the script run over the weekend#
set `date` # use backward quotes
if [ "$1" = "Sat" -o "$1" = "Sun" ]
then
echo "This report cannot be run over the weekend."
fi
一些有用的示例
示例 1:在脚本文档中出现的“逻辑”的最简单的形式(如本文任何示例中所示)是“if ... then”语句。先前的一个代码段检查是否存在一定数量的变量,然后将这些变量回显。假设我们对此稍微做一些修改,比如我们想回显变量,并且每次回显均减去最左边的变量,以显示一个倒的三角形。
虽然这听起来很简单,但实际并非如此;这是您在执行大规模处理时想实现的方式:处理第一个变量、转移、处理下一个变量……
出于演示的目的,能够按以下方式撰写脚本中的重要行:
#example11 - display declining variables, up to three
if [ "$#" -gt 3 ] # see if more than three variables are given
then
echo "You have given more than three variables."
exit
fi
echo $*
if test -n "$2"
then
shift
echo $*
fi
if test -n "$2"
then
shift
echo $*
fi
他将按以下方式执行:
$ example11 one
one
$
$ example11 one two
one two
two
$
$ example11 one two three
one two three
two three
three
$
$ example11 one two three four
You have given more than three variables.
$
出于检查的目的将数量限制为三个变量的原因是减少在例子中要检查的行数。一切都按部就班地进行,虽然他令人难以置信地混乱;用户因使用了超过程式依设计所能处理的变量数而得到警告,且脚本退出。假如变量数为 3 或更少,则运算的核心部分开始执行。
回显变量,执行测试以查看另一个变量是否存在。假如另一个变量存在,则执行一次转移,回显该变量,执行另一测试,等等。总共使用了 16 个有效行,而程式仅能处理不超过三个变量 — 很混乱。假设消除变量数的限制,程式能够处理任意数量的变量。经过一些修改,脚本被缩短(美化)了,并能处理任意数量的变量:
#example12 - display declining variables, any number
while [ "$#" -gt 0 ]
do
echo $*
shift
done
$ example12 1 2 3 4 5 6 7 8 9 0
1 2 3 4 5 6 7 8 9 0
2 3 4 5 6 7 8 9 0
3 4 5 6 7 8 9 0
4 5 6 7 8 9 0
5 6 7 8 9 0
6 7 8 9 0
7 8 9 0
8 9 0
9 0
0
现在减少到只有 5 个有效行,且消除了第一个脚本三个变量的限制,并在运行时要更高效。
示例 2:无论何时当在脚本内执行和处理相关的操作时,下一个操作将始终检查上一操作的状态,以确认他已成功完成。您能够通过检查 $? 的状态并验证他等于 0 来实现这一目的。例如,假如一个数据目录是否能访问很重要,
#example13
TEMP=LST
cd $TEMP
if [ $?-ne 0 ]
then
echo "Data directory could not be found."
Exit
fi
处理错误
资源
下载针对 Linux 的 Oracle 数据库 10g
Oracle 数据库 10g 第 1 版 (10.1.0.2) 现在可用于 Linux x86 和 Linux Itanium 平台;请在此从 OTN 上免费下载。
访问 Linux 技术中央
收藏本页,以获取关于 Linux 系统管理员最好应用的一般技术信息,连同关于 Oracle-on-Linux 产品群的具体技术信息。
相关文章
Linux 相关技术文章的存档
test 命令常常出现的错误事实上只有两种类型。第一种是未使用正确的评估类型,例如将字符串变量和整型变量进行比较或将带填充的字符串和不带填充的字符串进行比较。仔细评估您使用的变量将使您最终找到错误的根源,并让您能够解决这些问题。
第二种错误类型包括将方括号误认为别名之外的某个东西。方括号和其内容之间必须有一个空格;否则,他们将不能解释其中的对象。例如,
$ [ "$LOGNAME" -gt 9]
test:] missing
$
请注意,错误消息指示 test 存在问题,即使使用了别名 ]。这些问题很容易发现,因为错误消息准确地将这些问题显示出来,然后您能够增加必要的空格。
结论
要在 shell 脚本中构建逻辑,您必须添加条件语句。每一条这种语句的核心都是对条件的评估,以判断他是否存在 — 通过使用 test 命令完成评估。了解他和他的别名(左方括号 ([)的工作原理将使您能够撰写能够完成一些复杂操作的 shell 脚本。
原创粉丝点击