欢迎各位兄弟 发布技术文章
这里的技术是共享的
在 macOS(或任何 Unix-like 系统)的 shell 脚本中,[(单中括号)和 [[(双中括号)是条件测试的不同语法,主要区别如下:
[是传统 test 命令的别名(相当于 test expression 或 [ expression ])。
兼容性更强,可在所有 POSIX shell(如 sh、dash)中使用。
需要严格的语法(如变量加引号、空格分隔符)。
不支持高级功能(如正则匹配、逻辑组合符 &&/|| 直接使用)。
bash# 检查文件是否存在 if [ -f "/path/to/file" ]; then echo "文件存在" fi # 字符串比较(需加引号) name="hello" if [ "$name" = "hello" ]; then echo "字符串匹配" fi # 算术比较(需用 -eq/-lt 等) if [ "$num" -gt 10 ]; then echo "num 大于 10" fi
[[是 Bash/Zsh 等现代 shell 的扩展功能(非 POSIX 标准)。
更灵活:
变量无需加引号(自动处理空格)。
支持逻辑组合符 &&、||(无需转义)。
支持模式匹配(== 通配符)和正则匹配(=~)。
通常比 [ 更高效(由 shell 直接解析,不调用外部命令)。
bash# 字符串比较(无需引号) if [[ $name == hello ]]; then echo "字符串匹配" fi # 模式匹配(通配符) if [[ "$file" == *.txt ]]; then echo "是 .txt 文件" fi # 正则匹配 if [[ "$email" =~ ^[a-z]+@[a-z]+\.[a-z]+$ ]]; then echo "邮箱格式有效" fi # 逻辑组合 if [[ -f "$file" && "$num" -gt 10 ]]; then echo "文件存在且 num > 10" fi
| 特性 | [(单中括号) | [[(双中括号) |
|---|---|---|
| 兼容性 | POSIX(通用) | Bash/Zsh(非 POSIX) |
| 变量引号 | 必须加引号 | 可省略 |
| 逻辑操作符 | -a/-o(或转义) | 直接使用 &&/` |
| 模式匹配 | 不支持 | 支持 ==、=~ |
| 错误处理 | 更严格(易报错) | 更容错 |
用 [[:当脚本确定运行在 Bash/Zsh 环境时(更简洁、安全)。
用 [:需要兼容 纯 POSIX shell(如 /bin/sh)时。
在 macOS 的默认 shell(Zsh 或 Bash)中,推荐优先使用 [[。
if [[ "$file" == *.txt ]]; 其中 *.txt 是正则表达式吗
在 [[ "$file" == *.txt ]] 中,*.txt 不是正则表达式,而是 shell 的通配符模式(glob pattern)。
| 特性 | 通配符 (Glob) | 正则表达式 (Regex) |
|---|---|---|
| 用途 | 匹配文件名/字符串 | 匹配文本模式 |
| 语法 | 简单(*, ?, []) | 复杂(.*, +, \d 等) |
| 示例 | *.txt → 所有 .txt 文件 | ^[a-z]+\.txt$ → 字母开头的 .txt |
通配符 *.txt
* 匹配任意字符(包括空字符)。
示例:[[ "$file" == *.txt ]] 检查 $file 是否以 .txt 结尾,如 file.txt、a.txt。
正则表达式 =~
需用 =~ 操作符显式启用正则匹配。
示例:[[ "$file" =~ ^.*\.txt$ ]](等价于通配符 *.txt,但写法复杂)。
==)bashfile="document.txt" if [[ "$file" == *.txt ]]; then echo "是 .txt 文件(通配符匹配)" fi
=~)bashfile="123.txt" if [[ "$file" =~ ^[0-9]+\.txt$ ]]; then echo "是纯数字开头的 .txt 文件(正则匹配)" fi
[[ ... == *.txt ]] 是通配符,不是正则!
若想用正则,必须明确写 =~,例如:
bash[[ "$file" =~ .*\.txt ]] # 正则写法(功能等效于 `*.txt` 通配符)
== + *.txt → 通配符模式(简单文件名匹配)。
=~ + .*\.txt → 正则表达式(复杂文本模式匹配)。
在判断文件扩展名时,直接用通配符(== *.txt)更简洁;若需更复杂的模式(如数字开头),才用正则(=~)。