Shell脚本深入教程:Bash测试命令
Bash测试命令
test命令或功能等价的Bash内置命令[ ]
可以做条件测试,如果测试的结果为True,则退出状态码为0。
此外,还可以使用[[]]
来做条件测试,它比test多一个正则匹配的功能。此外,let、$[]、$(())
也可以做条件测试。但我的建议是只掌握一个测试方式,要么掌握[]
测试,要么掌握[[]]
。我个人是习惯于使用[]
,并在很偶尔做正则测试的时候用[[]]
,但更多正则测试我还是使用echo+grep/perl来完成的。
这些条件测试常用在if、while语句中,也常用在cmd1 && cmd2 || cmd3
格式的命令行中。
用法示例:
1 | sh_file=test.sh |
[]
和[[]]
中的条件测试语句都需要和开闭中括号使用空格隔开,否则语法解析错误。
无测试内容
1 | [ ] |
没有任何测试内容时,直接返回false。
true和false命令
true命令直接返回true,即退出状态码为0。
false命令直接返回false,即退出状态码非0。
1 | true |
文件类测试
条件表达式 | 含义 |
---|---|
-e file | 文件是否存在(exist) |
-f file | 文件是否存在且为普通文件(file) |
-d file | 文件是否存在且为目录(directory) |
-b file | 文件是否存在且为块设备block device |
-c file | 文件是否存在且为字符设备character device |
-S file | 文件是否存在且为套接字文件Socket |
-p file | 文件是否存在且为命名管道文件FIFO(pipe) |
-L file | 文件是否存在且是一个链接文件(Link) |
测试是否是终端
1 | if [ -t 1 ]; then # is terminal? |
文件属性类测试
条件表达式 | 含义 |
---|---|
-r file | 文件是否存在且当前用户可读 |
-w file | 文件是否存在且当前用户可写 |
-x file | 文件是否存在且当前用户可执行 |
-s file | 文件是否存在且大小大于0字节,即检测文件是否非空文件 |
-N file | 文件是否存在,且自上次read后是否被modify |
两文件之间的比较
条件表达式 | 含义 |
---|---|
file1 -nt file2 | (newer than)判断file1是否比file2新 |
file1 -ot file2 | (older than)判断file1是否比file2旧 |
file1 -ef file2 | (equal file)判断file1与file2是否为同一文件 |
数值大小比较
条件表达式 | 含义 |
---|---|
int1 -eq int2 | 两数值相等(equal) |
int1 -ne int2 | 两数值不等(not equal) |
int1 -gt int2 | n1大于n2(greater than) |
int1 -lt int2 | n1小于n2(less than) |
int1 -ge int2 | n1大于等于n2(greater than or equal) |
int1 -le int2 | n1小于等于n2(less than or equal) |
字符串比较
条件表达式 | 含义 |
---|---|
-z str | (zero)判定字符串是否为空?str为空串,则true |
str -n str |
判定字符串是否非空?str为串,则false。注:-n可省略 |
str1 = str2 str1 == str2 |
str1和str2是否相同,相同则返回true。『==』和『=』等价 |
str1 != str2 | str1是否不等于str2,若不等,则返回true |
str1 > str2 | str1字母顺序是否大于str2,若大于则返回true |
str1 < str2 | str1字母顺序是否小于str2,若小于则返回true |
逻辑运算符
条件表达式 | 含义 |
---|---|
-a或&& | (and)两表达式同时为true时才为true。 『-a』只能在test或[]中使用,&&只能在[[]]中使用 |
-o或|| | (or)两表达式任何一个true则为true。 『-o』只能在test或[]中使用,||只能在[[]]中使用 |
! | 对表达式取反 |
( ) | 改变表达式的优先级,为了防止被shell解析,应加上反斜线转义\( \) |
对于逻辑与和逻辑或,下面实现的效果是等价的:
1 | [ $a -gt 1 -a $a -lt 5 ] |
双中括号测试[[]]
双中括号也能进行测试,测试功能和[]
相比只有少数不同,但它有一个非常好用的功能:正则测试,正则测试后还能获取正则匹配到的内容。
我个人通常是习惯使用[]
进行测试的,只有在需要正则测试的时候才很偶尔使用[[]]
,大多数正则测试还是使用echo + grep/perl。
这里我介绍下[[]]
的正则测试功能,大家可以根据自己的喜好来决定使用哪种方式。
在[[]]
中,使用=~
符号开启正则测试功能,它使用的是扩展正则。
1 | [[ "hello123world" =~ [0-9]+ ]] |
=~
左边是待匹配的字符串或变量,右边是正则表达式。
正则表达式部分默认不加引号包围,如果加引号(无论是单双引号)包围,将和反斜线\
功能一样,对整个正则表达式进行转义。
比如:
1 | 匹配成功,正则元字符点能匹配任意字符 |
例如:
1 | [[ "abc1234,789" =~ [a-z]{1,}([0-9]+),([0-9]+) ]] |
条件测试注意事项
1.无论是[]
还是[[]]
,都建议对其内变量、字符串使用双引号包围。换句话说,能做字符串比较的时候,不要用数值比较。
例如:
1 | name="Ma long" |
上面的测试语句将报错,因为在变量替换阶段,$name
被替换为『Ma long』,但它们没有在引号内,于是进行单词拆分,这就等价于执行的是[ Ma long = "Ma long" ]
,显然这是错误的语法。所以,建议加上双引号:
1 | [ "$name" = "Ma long" ] |
2.数值比较时,建议双方同时加0,避免变量为空时报错。
例如,变量a为空,下面的表达式是错误的。因为它被shell解析后相当于[ -eq 7 ]
,而这是错误的语法。
1 | [ $a -eq 7 ] |
采取第一种建议,将$a
使用引号包围的话,还是错的。因为被shell解析后相当于[ "" -eq 7 ]
,字符串和数值无法比较。注意这里的报错和上面的错误信息不一样。
1 | [ "$a" -eq 7 ] |
所以最好的方法是将它改为字符串来测试,或者双方同时加0,由于此处有一方是常量数值,所以只需为变量部分加0即可。
1 | [ "$a" = "7" ] |
3.当变量可能为空的时候,强烈建议在变量的基础上加上其他辅助字符串。
上面的语句虽然能正确测试。其实更安全的方法是采用下面的形式:
1 | [ "a$a" = "a7" ] # 判断a是否为7 |
4.另外,在[]
和[[]]
中,每个地方都有空格。这不是书写建议,而是强制要求的格式。