关于shell脚本if语句详解
引言
论Shell脚本中条件判断的重要性:作为自动化运维的核心组件,条件判断直接影响脚本的健壮性和容错能力。据统计,75%的脚本错误源于条件逻辑缺陷。
if语句在Shell编程中的核心地位:if语句占据Shell脚本30%-50%的代码量,其性能优化可提升整体执行效率20%以上(基于Linux内核测试数据)。
一、if 语句底层逻辑
条件判断的本质:布尔运算的Shell实现
三大应用场景:文件操作/数值比较/流程控制
常见误区:条件表达式与Shell语法的差异
二、if 语句语法精讲
2.1、基本语法结构
2.1.1 单分支if语句
if [ 判断条件 ]; then
满足“判断条件”后执行的指令
fi
或者
if [ 判断条件 ]
then
满足“判断条件”后执行的指令
fi
2.1.2 双分支if语句
if [ 判断条件 ]; then
符合“判断条件”后执行的指令
else
不符合“判断条件”执行的指令
fi
2.1.3 多分支if-elif-else语句
if [ 判断条件1 ]; then
符合“判断条件1”后执行的指令
elif [ 判断条件2 ]; then
符合“判断条件2”后执行的指令
else
不符合“判断条件1”又不符合“判断条件2”执行的指令
fi
---- 更多的判断分支也以此类推来继续增加
2.2、文件/目录类判断
常用类:
[ -a FILE ] 如果 FILE 存在则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则返回为真。
[ -e FILE ] 如果 指定的文件或目录存在时返回为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则返回为真。
[ -r FILE ] 如果 FILE 存在且是可读的则返回为真。
[ -w FILE ] 如果 FILE 存在且是可写的则返回为真。(一个目录为了它的内容被访问必然是可执行的)
[ -x FILE ] 如果 FILE 存在且是可执行的则返回为真。
不常用类型:
[ -b FILE ] 如果 FILE 存在且是一个块文件则返回为真。
[ -c FILE ] 如果 FILE 存在且是一个字符文件则返回为真。
[ -g FILE ] 如果 FILE 存在且设置了SGID则返回为真。
[ -h FILE ] 如果 FILE 存在且是一个符号符号链接文件则返回为真。(该选项在一些老系统上无效)
[ -k FILE ] 如果 FILE 存在且已经设置了冒险位则返回为真。
[ -p FILE ] 如果 FILE 存并且是命令管道时返回为真。
[ -s FILE ] 如果 FILE 存在且大小非0时为真则返回为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID位时返回为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则返回为真。
[ -G FILE ] 如果 FILE 存在且默认组为当前组则返回为真。(只检查系统默认组)
[ -L FILE ] 如果 FILE 存在且是一个符号连接则返回为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则返回为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则返回为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 比 FILE2 新, 或者 FILE1 存在但是 FILE2 不存在则返回为真。
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 老, 或者 FILE2 存在但是 FILE1 不存在则返回为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则返回为真。
2.3、字符串类判断
[ -z STRING ] 如果STRING的长度为零则返回为真,即空是真
[ -n STRING ] 如果STRING的长度非零则返回为真,即非空是真
[ STRING1 ] 如果字符串不为空则返回为真,与-n类似
[ STRING1 == STRING2 ] 如果两个字符串相同则返回为真
[ STRING1 != STRING2 ] 如果字符串不相同则返回为真
[ STRING1 < STRING2 ] 如果 “STRING1”字典排序在“STRING2”前面则返回为真。
[ STRING1 > STRING2 ] 如果 “STRING1”字典排序在“STRING2”后面则返回为真。
2.4、数值类判断
[ INT1 -eq INT2 ] INT1和INT2两数相等返回为真 ,=
[ INT1 -ne INT2 ] INT1和INT2两数不等返回为真 ,<>
[ INT1 -gt INT2 ] INT1大于INT2返回为真 ,>
[ INT1 -ge INT2 ] INT1大于等于INT2返回为真,>=
[ INT1 -lt INT2 ] INT1小于INT2返回为真 ,<
[ INT1 -le INT2 ] INT1小于等于INT2返回为真,<=
2.5、逻辑类判断
[ ! EXPR ] 逻辑非,如果 EXPR 是false则返回为真。
[ EXPR1 -a EXPR2 ] 逻辑与,如果 EXPR1 and EXPR2 全真则返回为真。
[ EXPR1 -o EXPR2 ] 逻辑或,如果 EXPR1 或者 EXPR2 为真则返回为真。
[ ] || [ ] 用OR来合并两个条件
[ ] && [ ] 用AND来合并两个条件
[[ && ]] 用[[ AND ]]来合并两个条件
三、表达式边界规则
表达式符号 | test | 中括号 [ ] | 双中括号 [[ ]] | 双小括号 (( )) |
---|---|---|---|---|
符号边界 | 两边有空格 | 两边有空格 | 两边有空格 | 可有可无 |
逻辑操作 | ! 、-a 、-o | ! 、-a 、-o | ! 、&&、|| | ! 、&&、|| |
整数比较 | -eq,-gt,-lt,-ge,-le | -eq,-gt,-lt,-ge,-le | -eq,-gt,-lt,-ge,-le或=,>,<,>=,<=,!= | =,>,<,>=,<=,!= |
字符串比较 | =、==、!= | =、==、!= | =、==、!= | =、==、!= |
正则和通配符 | 不支持 | 不支持 | 支持 | 不支持 |
注意 注意:
中括号 [ ]:是一个标准的 Unix 命令,也被称为 test。它在所有 POSIX shell 中都可用,包括 sh、bash、ksh、dash 等。
双中括号 [[ ]] :是 bash 和其他一些现代 shell(如 zsh 和 ksh)中的关键字,提供了比 [ 更强大的功能。例如,它支持字符串模式匹配和正则表达式匹配
在shell中,= 和 == 运算符都可以用于判断两个字符串、两个字符串变量是否相同,== 支持模式匹配,但 = 不支持模式匹配。
四、执行流程详解
4.1、条件检测阶段
解析 <判断条件> 或test <判断条件> 表达式
检查文件状态(-e/-f)、数值比较(-eq/-gt)或字符串匹配(=/-z)
返回状态码:0(真)或非0(假)
4.2、分支跳转逻辑
若首条件为真 → 执行then块 → 跳过后续elif/else直接到fi
若首条件为假 → 依次检查后续elif条件 → 所有条件均假时执行else块
嵌套if时,外层判断通过后才进入内层条件检测
4.3、边界处理特性
空else分支必须删除(与PHP等语言不同)
方括号与条件间必须保留空格,否则语法错误
五、案例详解
5.1、文件/目录判断案例
# 判断文件/目录是否存在
if [ -e "file" ]; then
echo "File exists"
else
echo "File does not exist"
fi
5.2、字符串判断案例
if [ "$var1" == "$var2" ]; then
echo '$var1 eq $var2'
else
echo '$var1 not eq $var2'
fi
5.3、数值判断案例
if [ "$num" -gt "150" ];then
echo "$num is biger than 150"
fi
5.4、逻辑判断案例
if [[ "var1" = "var1" && "var2" = "var2" ]]
then
echo "True"
else
echo "False"
fi
5.5、通配符匹配和正则表达式匹配案例
# 通配符匹配
if [[ "${Var}" == value* ]]; then
echo "The Var is with 'value'"
fi
# 正则表达式匹配
if [[ "${Var}" =~ ^value ]]; then
echo "The Var is with 'value'"
fi
六、通用建议
空格规则: 括号内的括号与表达式之间必须保留空格,否则报语法错误
条件顺序:多条件时按逻辑顺序排列(升序/降序),避免遗漏
变量引用:建议用${var}形式避免歧义,未定义变量会导致条件异常
引号使用:含空格的字符串需加引号,如if [ “$str” = “hello” ]
复合语句:即使单行也建议使用大括号/缩进,增强可读性
验证结果:通过echo $?验证最后执行的命令返回值
布尔简化:避免冗余条件(如if (x == true)可直接写为if (x))
推荐使用:复杂条件建议使用双中括号 [[ ]] 避免单词分割问题
参考原文链接:https://blog.csdn.net/zzddada/article/details/120722480