像在 Java 或 C# 的一些编程语言中都有单元测试的支持来让我们测试一段代码的运行结果是否满足我们的期望,而在 bash 中,虽然没有单元测试,但它对一些简单的条件测试提供了支持。
测试命令的格式有如下几种:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
中括号中的
EXPRESSION
前后必须有空白字符。
数值测试
以 test
命令为例测试判断 1>3
与 1<3
的结果。
[root@localhost ~]# test 1 -gt 3
[root@localhost ~]# echo $?
1
[root@localhost ~]# test 1 -lt 3
[root@localhost ~]# echo $?
0
test
命令的方式需使用选项来指定比较运算符类型,如上示例中-gt
代指>
,-lt
代指<
。
数值测试时test
命令支持的选项如下:
-gt
:是否大于;-ge
:是否大于等于;-eq
:是否等于;-ne
:是否不等于;-lt
:是否小于;-le
:是否小于等于;
以 [ EXPRESSION ]
的方式为例:
[root@localhost ~]# [ 1 -gt 3 ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [ 1 -lt 3 ]
[root@localhost ~]# echo $?
0
它支持的选项与
test
命令相同。
以 [[ EXPRESSION ]]
的方式为例:
[root@localhost ~]# [[ 1 > 3 ]]
[root@localhost ~]# echo $?
1
[root@localhost ~]# [[ 1 < 3 ]]
[root@localhost ~]# echo $?
0
[[ EXPRESSION ]]
的方式可直接使用算数运算符进行比较,而不需使用选项,可读性更高。
结果为真时$?
的结果为0
,为假时$?
的结果为1
。
字符串测试
以 test
命令为例测试 name
与 myname
变量是否为空:
[root@localhost ~]# name='zze'
[root@localhost ~]# test -z $name
[root@localhost ~]# echo $?
1
[root@localhost ~]# test -z $myname
[root@localhost ~]# echo $?
0
字符串测试时
test
命令支持的选项如下:
-z
:测试字符串是否为空,空则为真,不空则为假;-n
:测试字符串是否不空,不空则为真,空则为假;除了支持上述选项外,还可通过操作符比较,如下:
STR1==STR2
:STR1
是否等于STR2
;
STR1>STR2
:STR1
是否大于STR2
,用首个字符对应的 ASCII 码值比较 ;
STR1<STR2
:STR1
是否小于STR2
,用首个字符对应的 ASCII 码值比较 ;
STR1!=STR2
:STR1
是否不等于STR2
;
STR=~PATTERN
:左侧字符串STR
能否被右侧的PATTERN
所匹配,此表达式一般用于[[ EXPRESSION ]]
中;
以 [ EXPRESSION ]
的方式为例:
[root@localhost ~]# name='zze'
[root@localhost ~]# [ -z "$name" ]
[root@localhost ~]# echo $?
1
[root@localhost ~]# echo $myname
[root@localhost ~]# [ -z "$myname" ]
[root@localhost ~]# echo $?
0
以 [[ EXPRESSION ]]
测试变量 name
是否已 z
或 a
开头,例:
[root@localhost ~]# [[ "$name" =~ ^z.* ]]
[root@localhost ~]# echo $?
0
[root@localhost ~]# [[ "$name" =~ ^a.* ]]
[root@localhost ~]# echo $?
1
文件测试
以 test
命令为例分别测试 /etc/passwd
文件和 /etc/password
文件是否存在为例:
[root@localhost ~]# test -a /etc/passwd
[root@localhost ~]# echo $?
0
[root@localhost ~]# test -a /etc/password
[root@localhost ~]# echo $?
1
文件测试相对于数值和字符串测试来说稍显复杂,主要通过不同的选项来做不同的测试,可大致分为以下几类:
存在性测试
-a
:判断文件是否存在,存在则为真,不存在则为假;-e
:同-a
;-s
:判断文件是否存在且不为空;
类别测试
-b
:判断文件是否为块设备文件;-c
:判断文件是否为字符设备文件;-d
:判断文件是否是一个目录;-f
:判断文件是否只是一个普通文件;-h
或-L
:判断文件是否是为符号链接文件;-p
:判断文件是否为命名管道文件;-S
:判断文件是否为套接字文件;
普通权限测试
-r
:判断当前用户对该文件是否拥有读权限;-w
:判断当前用户对该文件是否拥有写权限;-x
:判断当前用户对该文件是否拥有执行权限;
特殊权限测试
-g
:判断当前用户对该文件是否拥有sgid
权限;-u
:判断当前用户对该文件是否拥有suid
权限;-k
:判断当前用户对该文件是否拥有sticky
权限;
文件状态测试
-t
:要注意的是使用该选项时参数并不是一个普通文件,而是文件描述符(file descriptor),而该选项的作用就是判断指定文件描述符是否已被打开并与某终端相关联;-N
:判断从上一次被读取后至今是否被修改过;-O
:判断当前用户是否是该文件的属主;-G
:判断当前用户是否在该文件属组中;
在前面其实有提到过,在 linux 中标准输入的文件描述符为
0
,标准输出的文件描述符为1
,标准错误输出的文件描述符为2
,而打开的其它文件都有一个文件描述符与之对应。
以标准输入的文件描述符0
为例,测试它是否已被打开并与某终端相关联:[root@localhost ~]# test -t 0 [root@localhost ~]# echo $? 0
因为标准输入的来源其实就是键盘,所以在终端使用键盘键入命令的情况下标准输入的文件描述符肯定是为已被打开且与当前终端相关联了的,所以输出的结果为真;
双目测试
FILE1 -ef FILE2
:判断FILE1
与FILE2
是否指向同一个设备上的相同 inode 号;FILE1 -nt FILE2
:判断FILE1
是否新与FILE2
;FILE1 -ot FILE2
:判断FILE1
是否旧于FILE2
;
组合测试条件
方式一:
COMMAND1 && COMMAND2
: 与运算,判断COMMAND1
和COMMAND2
是否都为真;COMMAND1 || COMMAND2
:或运算,判断COMMAND1
和COMMAND2
中是否有一个为真;! COMMAND
:非运算,判断COMMAND
是否为假;
例:判断是否存在 /etc/passwd
并且不存在 /etc/password
文件。
[root@localhost ~]# test ! -e /etc/password && test -e /etc/passwd
[root@localhost ~]# echo $?
0
方式二:
[EXPRESSION1 -a EXPRESSION2]
:与运算,判断EXPRESSION1
和EXPRESSION2
是否都为真;[EXPRESSION1 -o EX{RESSION2]
:或运算,判断EXPRESSION1
和EXPRESSION2
中是否有一个为真;[ ! EXPRESSION ]
:非运算,判断EXPRESSION
是否为假;
例:判断是否存在 /etc/passwd
并且不存在 /etc/password
文件。
[root@localhost ~]# [ ! -e /etc/password -a -e /etc/passwd ]
[root@localhost ~]# echo $?
0
同下:
[root@localhost ~]# test ! -e /etc/password -a -e /etc/passwd
[root@localhost ~]# echo $?
0
即可以通过 -a
和 -o
选项来连接两个表达式,而不能使用 &&
和 ||
。
[ EXPRESSION ]
这种方式的使用和test
命令相同,test
命令有的选项都可以直接在[EXPRESSION]
中使用;
而[[ EXPRESSION ]]
这种方式与test
和[ EXPRESSION ]
都不同,它支持原生符号进行比较和运算,如在数值测试中>
就表示大于,而不用使用-gt
选项,在逻辑运算中&&
就表示与运算,而不用使用-a
选项。
评论区