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.另外,在[]和[[]]中,每个地方都有空格。这不是书写建议,而是强制要求的格式。


