为何dash的test -d命令无文件参数时返回0?
问题背景
我编写了一个接收目录路径作为参数的小型dash脚本,跳过参数解析直接测试目录属性时发现:未传入目录参数时,脚本仍报告目录存在。具体测试代码如下:
#!/bin/sh # dash script zero=0 test $zero -eq 0 echo $? # prints 0 zerostr="000" test $zerostr -eq 0 echo $? # prints 0 test echo $? # prints 1 (as documented) test -d echo $? # prints 0 (but why? the unspecified directory 'exists'? wouldn't it be more consistent to print 1 instead?) test -d $9 # what is the best way to check if an argument was indeed passed in on the command line? echo $? # prints 0 even when $9 was not provided to the script
核心疑问解答:为何
test -d无参数时返回0? 这并非bug,而是dash对test命令的特定实现行为。根据POSIX标准,当单目运算符(如-d)缺少对应的操作数时,属于未定义行为——标准没有强制要求返回值,不同shell可自行实现。
dash的test在处理这种情况时,会将无操作数的单目运算符判定为“真”(返回0),这和test无参数时返回1的情况不冲突:后者是POSIX明确规定的行为(无参数的test必须返回1),而单目运算符缺操作数的情况不在强制规范范围内。
兼容性风险:修改该行为是否可行?
如果建议让test -d无参数时返回1,会严重破坏现有兼容性,原因在于:
- 很多老旧shell脚本可能存在
test -d $some_var这类写法,当$some_var为空时,实际执行的就是test -d。若原本返回0(判定为“目录存在”),修改后返回1(判定为“目录不存在”),会直接反转这类脚本的逻辑,导致功能异常。 - POSIX未定义该场景的行为,意味着现有脚本依赖dash的实现是合法的,修改会违背“最小破坏性”的软件维护原则,Debian团队基本不会接受这类变更。
测试文件属性前的参数检查方法
要避免这类问题,必须先验证参数是否存在且非空,再进行属性检查,常用方法有:
- 检查参数数量:确保脚本接收到足够的参数,比如要求至少传入1个路径参数:
if [ $# -lt 1 ]; then echo "错误:请传入目录路径参数" >&2 exit 1 fi - 检查参数是否非空:针对特定参数(比如第一个参数)验证其不为空字符串:
if [ -z "$1" ]; then echo "错误:目录路径不能为空" >&2 exit 1 fi - 结合属性检查:将参数非空验证和目录检查合并,注意必须给参数加引号,防止参数为空时触发
test -d的异常行为:if [ -n "$1" ] && [ -d "$1" ]; then echo "目录 $1 存在" else echo "目录不存在或参数为空" >&2 fi
内容的提问来源于stack exchange,提问作者lonious
相关产品推荐
相关产品推荐

