判断语句
Shell 中的判断语句:test、[] 与 [[]] 的全面用法
在 Shell 脚本中,判断语句是实现条件逻辑的基础。无论是文件类型检查、权限验证,还是数值 / 字符串比较,都需要通过判断语句实现。本文详细讲解 test 命令、[ ] 和 [[ ]] 三种判断方式的用法及差异。
判断语句的三种形式
Shell 中常用的判断形式有三种,功能类似但语法略有差异:
| 形式 | 说明 | 兼容性 |
|---|---|---|
test 条件 |
基础判断命令 | 所有 Shell 兼容 |
[ 条件 ] |
test 命令的简化写法(注意空格) |
所有 Shell 兼容 |
[[ 条件 ]] |
Bash 扩展语法,支持更多特性 | 仅 Bash、Zsh 等现代 Shell 支持 |
基本用法示例
三种形式可以互换,结果完全一致:
# 判断文件是否为目录
test -d /etc && echo "是目录" || echo "不是目录"
[ -d /etc ] && echo "是目录" || echo "不是目录"
[[ -d /etc ]] && echo "是目录" || echo "不是目录"
输出均为:是目录
文件类型判断
用于检查文件是否存在及类型(目录、普通文件等),常用选项如下:
| 选项 | 含义 | 示例 |
|---|---|---|
-e 文件 |
文件或目录是否存在 | [ -e /etc/passwd ] → 检查密码文件是否存在 |
-d 目录 |
是否为目录且存在 | [ -d /tmp ] → 检查 /tmp 是否为目录 |
-f 文件 |
是否为普通文件且存在 | [ -f ~/.bashrc ] → 检查用户配置文件是否为普通文件 |
-s 文件 |
文件是否存在且非空(大小 > 0) | [ -s log.txt ] → 检查日志文件是否有内容 |
-L 链接 |
是否为符号链接 | [ -L /usr/bin/python ] → 检查 Python 命令是否为软链接 |
-b 设备 |
是否为块设备(如硬盘) | [ -b /dev/sda ] → 检查第一块硬盘 |
-c 设备 |
是否为字符设备(如键盘) | [ -c /dev/tty0 ] → 检查终端设备 |
示例:检查文件状态并输出信息
file="data.txt"
if [ -e "$file" ]; then
echo "$file 存在"
if [ -f "$file" ]; then
echo "$file 是普通文件"
if [ -s "$file" ]; then
echo "$file 非空"
else
echo "$file 为空文件"
fi
else
echo "$file 不是普通文件"
fi
else
echo "$file 不存在"
fi
文件权限判断
检查文件是否拥有读、写、执行权限:
| 选项 | 含义 | 示例 |
|---|---|---|
-r 文件 |
是否有读权限 | [ -r /etc/shadow ] → 普通用户通常返回 false |
-w 文件 |
是否有写权限 | [ -w ~/test.txt ] → 检查用户目录下文件是否可写 |
-x 文件 |
是否有执行权限 | [ -x /usr/bin/ls ] → 检查 ls 命令是否可执行 |
示例:检查脚本是否可执行,若不可执行则添加权限
script="deploy.sh"
if [ -f "$script" ]; then
if [ ! -x "$script" ]; then # "!" 表示取反
echo "添加执行权限..."
chmod +x "$script"
else
echo "$script 已可执行"
fi
fi
数值比较
用于整数之间的比较(不支持浮点数):
| 选项 | 含义 | 示例 |
|---|---|---|
-eq |
等于(equal) | [ 10 -eq 10 ] → true |
-ne |
不等于(not equal) | [ 10 -ne 20 ] → true |
-gt |
大于(greater than) | [ 20 -gt 10 ] → true |
-lt |
小于(less than) | [ 5 -lt 10 ] → true |
-ge |
大于等于(greater or equal) | [ 10 -ge 10 ] → true |
-le |
小于等于(less or equal) | [ 5 -le 10 ] → true |
示例:比较两个数字大小
a=15
b=20
if [ $a -gt $b ]; then
echo "$a 大于 $b"
elif [ $a -lt $b ]; then
echo "$a 小于 $b"
else
echo "$a 等于 $b"
fi
# 输出:15 小于 20
字符串比较
用于字符串的 equality、空值等判断:
| 选项 | 含义 | 示例 |
|---|---|---|
= 或 == |
字符串相等(== 仅 [[ ]] 推荐) |
[ "abc" = "abc" ] → true |
!= |
字符串不等 | [ "abc" != "def" ] → true |
-z 字符串 |
字符串长度为 0(空字符串) | [ -z "" ] → true |
-n 字符串 |
字符串长度不为 0(非空) | [ -n "hello" ] → true |
示例:检查用户输入是否为空
read -p "请输入姓名:" name
if [ -z "$name" ]; then # 注意变量用双引号包裹,避免空值导致语法错误
echo "姓名不能为空!"
else
echo "你好,$name!"
fi
逻辑组合判断
多个条件的与、或、非组合:
| 逻辑 | test/[ ] 写法 |
[[ ]] 写法 |
说明 | ||
|---|---|---|---|---|---|
| 与 | 条件1 -a 条件2 |
条件1 && 条件2 |
两个条件都为真才成立 | ||
| 或 | 条件1 -o 条件2 |
` 条件 1 | 条件 2` | 至少一个条件为真 | |
| 非 | ! 条件 |
! 条件 |
条件为假时成立 |
示例:多条件组合判断
# 使用 [ ] 组合条件(-a 表示与)
if [ -f "file.txt" -a -r "file.txt" ]; then
echo "file.txt 是可读的普通文件"
fi
# 使用 [[ ]] 组合条件(&& 表示与)
if [[ -f "file.txt" && -r "file.txt" ]]; then
echo "file.txt 是可读的普通文件"
fi
[[ ]] 的高级特性
[[ ]] 是 Bash 扩展语法,支持更多便捷功能:
字符串包含判断
无需借助 grep,直接用通配符 * 匹配:
str="hello world"
# 判断 str 是否包含 "world"
if [[ $str == *world* ]]; then
echo "包含 'world'"
fi
# 输出:包含 'world'
正则表达式匹配
使用 =~ 支持正则匹配:
email="test@example.com"
# 简单验证邮箱格式
if [[ $email =~ ^[a-zA-Z0-9_]+@[a-zA-Z0-9]+\.[a-zA-Z]+$ ]]; then
echo "邮箱格式正确"
else
echo "邮箱格式错误"
fi
无需转义特殊字符
[[ ]] 中特殊字符(如 *、?)无需转义,直接使用:
# 判断文件名是否以 .sh 结尾
file="script.sh"
if [[ $file == *.sh ]]; then # * 无需转义
echo "$file 是 Shell 脚本"
fi
常见错误与注意事项
- 空格问题:
[ 条件 ]和[[ 条件 ]]中,[/[[后、]/]]前必须有空格,如[ -f file ]正确,[-f file]错误。
- 变量引用:
- 字符串变量和可能为空的变量必须用双引号包裹,避免语法错误:
[ "$name" = "root" ]正确,[ $name = "root" ]可能报错(若name为空)。
- 字符串变量和可能为空的变量必须用双引号包裹,避免语法错误:
- 兼容性:
[[ ]]是 Bash 扩展,若脚本需在sh等兼容 Shell 中运行,应使用[ ]。
- 数值与字符串混淆:
- 数值比较用
-eq/-gt等,字符串比较用=/!=,不可混用。
- 数值比较用