bash中[[ -d foo-* ]]与[ -d foo-* ]返回结果差异的原因咨询
为什么
[[ -d foo-* ]]返回false但[ -d foo-* ]返回true? 这个问题我当初刚深挖bash细节的时候也踩过坑,核心原因是bash里[[和[这两个条件判断工具在通配符(路径扩展)处理逻辑上完全不一样,咱们一步步拆解清楚:
1. 先看[ -d foo-* ]的执行逻辑
[其实是POSIX标准test命令的别名(你直接写test -d foo-*效果完全一致)。它的执行流程是:
- 首先shell会优先对
foo-*做路径扩展(globbing):如果当前目录下存在匹配foo-*的目录(比如你的foo-bar),shell会把foo-*直接替换成匹配到的具体目录名,所以实际执行的命令变成了[ -d foo-bar ]。 - 接下来
test命令检查foo-bar是不是目录,显然符合条件,所以返回true($?=0)。
小补充:如果当前目录下有多个匹配
foo-*的项(比如foo-bar和foo-baz),[ -d foo-* ]会直接报错——因为test命令的-d选项只接受一个参数,展开后参数数量超标了。
2. 再看[[ -d foo-* ]]的执行逻辑
[[是bash特有的内置关键字,它的设计逻辑和[完全不同,其中一个关键差异就是通配符不会自动触发路径扩展:
- 在
[[的条件表达式里,foo-*会被当作字面字符串处理,也就是说bash会去检查当前目录下有没有一个名字就是foo-*的目录——显然你没有这个目录,所以[[ -d foo-* ]]返回false($?=1)。 - 如果你想在
[[里实现和[一样的通配符匹配效果,得手动触发路径扩展,比如先把匹配结果存到数组里再判断:shopt -s nullglob # 确保没有匹配时数组为空,不会保留原通配符字符串 dir_matches=(foo-*) [[ ${#dir_matches[@]} -gt 0 && -d "${dir_matches[0]}" ]]
核心差异总结
| 工具 | 通配符处理逻辑 |
|---|---|
[/test | shell先做路径扩展,再把结果传给命令处理 |
[[ | 通配符默认作为字面量处理,仅在模式匹配(比如[[ $var == foo-* ]])场景下生效 |
你可以自己验证这个差异:执行echo [ -d foo-* ]和echo [[ -d foo-* ]],前者会输出[ -d foo-bar ](已经完成路径扩展),后者还是[[ -d foo-* ]](保留原通配符)。
内容的提问来源于stack exchange,提问作者René Nyffenegger
相关产品推荐
相关产品推荐

