Shell test命令¶
test是Shell内置命令, 用来检测某个条件是否成立.
test通常和if语句一起使用, 并且大部分if语句都依赖test.
test命令有很多选项, 可以进行数值, 字符串和文件三个方面的检测.
test命令的用法为:
test expression
当test判断expression成立时, 退出状态为0, 否则为非0值.
test命令也可以简写为[], 它的用法为:
[ expression ]
注意[]和expression之间的空格, 这两个空格是必须的, 否则会导致语法错误.
[]的写法更加简洁, 比test使用频率高.
与文件检测相关的test选项¶
- 文件类型判断
| 选项 | 作用 |
-b filename |
判断文件是否存在, 并且是否为块设备文件. |
-c filename |
判断文件是否存在, 并且是否为字符设备文件. |
-d filename |
判断文件是否存在, 并且是否为目录文件. |
-e filename |
判断文件是否存在. |
-f filename |
判断文件是否存在, 并且是否为普通文件. |
-L filename |
判断文件是否存在, 并且是否为符号链接文件. |
-p filename |
判断文件是否存在, 并且是否为管道文件. |
-s filename |
判断文件是否存在, 并且是否为非空. |
-S filename |
判断文件是否存在, 并且是否为套接字文件. |
- 文件权限判断
| 选项 | 作用 |
-r filename |
判断文件是否存在, 并且是否有读权限. |
-w filename |
判断文件是否存在, 并且是否有写权限. |
-x filename |
判断文件是否存在, 并且是否有执行权限. |
-u filename |
判断文件是否存在, 并且是否有SUID权限. |
-g filename |
判断文件是否存在, 并且是否有SGID权限. |
-k filename |
判断文件是否存在, 并且是否有SBIT权限. |
- 文件比较
| 选项 | 作用 |
filename1 -nt filename2 |
判断filename1的修改时间是否比filename2的新. |
filename1 -ot filename2 |
判断filename1的修改时间是否比filename2的旧. |
filename1 -ef filename2 |
判断 可以理解为两个文件是否为同一个文件, 这个判断用于判断硬链接是很好的方法. |
Example:
#!/usr/bin/env bash
read filename
read url
if [ -w $filename -a -n $url ]
then
echo $url > $filename
echo "写入成功"
else
echo "写入失败"
fi
与数值比较相关的test选项¶
| 选项 | 作用 |
num1 -eq num2 |
equal, 判断num1是否等于num2. |
num1 -ne num2 |
not equal, 判断num1是否不等于num2. |
num1 -gt num2 |
greather than, 判断num1是否大于num2. |
num1 -ge num2 |
greather equal, 判断num1是否大于等于num2. |
num1 -lt num2 |
less than, 判断num1是否小于num2. |
num1 -le num2 |
less equal, 判断num1是否小于等于num2. |
注意, test只能用来比较整数, 小数比较还得依赖bc命令.
Example:
#!/usr/bin/env bash
read a b
if [ $a -eq $b ]
then
echo "两个数相等"
else
echo "两个数不相等"
fi
与字符串判断相关的test选项¶
| 选项 | 作用 |
-z str |
判断字符串str是否为空. |
-n str |
判断字符串str是否为非空. |
str1 = str2 |
判断str1和str2是否相等. |
str1 == str2 |
判断str1和str2是否相等. |
str1 != str2 |
判断str1和str2是否不等. |
str1 \> str2 |
判断str1是否大于str2.
|
str1 /< str2 |
判断str1是否小于str2.
|
在C/C++, Python等编程语言中, ==/>/<都被用来比较数字,
而在Shell的test命令中, 它们不能比较数字, 只能用来比较字符串.
与逻辑运算相关的test选项¶
| 选项 | 说明 |
expression1 -a expression2 |
逻辑与, 表达式 最终的结果才是成立的. |
expression1 -o expression2 |
逻辑或, 表达式 最终的结果就成立. |
!expression |
逻辑非, 对expression进行取反. |
Example:
#/usr/bin/env bash
read str1
read str2
# 检测字符串是否为空
if [ -z "$str1" -o -z "$str2" ]
then
echo "字符串不能为空"
exit 0
fi
# 比较字符串
if [ $str1 == $str2 ]
then
echo "字符串相等"
else
echo "字符串不相等"
fi
在test中使用变量建议用双引号包围起来¶
test和[]都是命令, 一个命令本质上对应一个程序或者一个函数.
即使是一个程序, 它也有入口函数, 例如C语言程序的入口函数是main(), 运行C语言程序就从main()函数开始,
所以也可以将一个程序等效为一个函数, 这样我们就不用区分函数和程序了, 直接将一个命令和一个函数对应起来即可.
使用一个命令时, 命令后面附带的选项和参数最终都会作为实参传递给函数.
假设test命令对应的函数是func(), 使用test -z $str命令时, 会先将变量$str替换成字符串:
- 如果
$str是一个正常的字符串, 比如abc123, 那么替换后的效果就是test -z abc123, 调用func函数的形式就是func("-z abc123").test命令后面附带的所有选项和参数会被看成一个整体, 并作为实参传递进函数;- 如果
$str是一个空字符串, 那么替换后的效果就是test -z, 调用func()函数的形式就是func("-z"), 这就比较奇怪了, 因为-z选项没有和参数成对出现,func()在分析时就会出错.
如果我们给变量$str加上双引号, 当$str是空字符串时, test -z "$str"就会被替换为test -z "",调用func()函数的形式就是func("-z \"\""),
很显然, -z选项后面跟的是一个空字符串, 这样func()在分析时就不会出错了.
所以, 当在test命令中使用变量时, 强烈建议将变量用双引号包围起来, 这样能避免变量为空值时导致的很多奇葩问题.
总结¶
test命令比较奇葩, >/</==只能用来比较字符串, 不能用来比较数字, 比较数字需要使用-eq, -gt等选项;
不管是比较字符串还是数字, test都不支持>=和<=.
对于整型数字的比较, 建议使用(()), (())支持各种运算, 写法也符合数学规则, 用起来更加方便.
几乎完全兼容test, 并且比test更加强大, 比test更加灵活的是: [[]], [[]]不是命令, 而是Shell关键字.