公司动态
Shell条件语句详解:从基础语法到实战技巧
1. Shell条件语句基础概念在Linux/Unix系统管理中Shell脚本的自动化能力很大程度上依赖于条件判断逻辑。与大多数编程语言不同Shell的条件语句有其独特的语法结构和行为特点这也是新手最容易踩坑的地方之一。Shell条件语句的核心作用是让脚本能够根据不同的系统状态、文件存在性、变量取值等情况做出动态决策。比如当磁盘空间不足时发送告警、根据用户输入执行不同操作、或者仅在特定文件存在时才继续执行后续流程。这些看似简单的判断逻辑在实际系统运维中能构建出复杂的自动化工作流。条件语句主要分为三类基础结构if-then-fi 基础判断if-then-else-fi 二选一分支if-elif-else-fi 多条件分支每种结构都有其特定的使用场景和语法要求。值得注意的是Shell中的条件判断本质上是在检查命令的退出状态码0表示成功非0表示失败这与传统编程语言中基于布尔值的判断有根本区别。理解这一点对编写正确的条件语句至关重要。2. if语句的语法详解与实战2.1 基础if语法结构最基本的if语句格式如下if [ condition ]; then # 条件为真时执行的命令 fi这里的方括号[ ]实际上是test命令的另一种写法condition部分可以使用各种测试表达式。特别注意[和]前后必须有空格then可以写在下一行但如果与if同行则需要分号分隔语句以fiif倒写结束一个检查文件是否存在的实际例子if [ -f /var/log/syslog ]; then echo 系统日志文件存在 fi2.2 条件测试的多种形式Shell提供了丰富的条件测试表达式主要分为几类文件测试-e file文件是否存在-f file是否是普通文件-d file是否是目录-r file是否可读-w file是否可写-x file是否可执行-s file文件大小是否大于0字符串比较-z string字符串长度是否为0-n string字符串长度是否非0str1 str2字符串相等str1 ! str2字符串不等数值比较num1 -eq num2等于num1 -ne num2不等于num1 -gt num2大于num1 -ge num2大于等于num1 -lt num2小于num1 -le num2小于等于组合条件! expr逻辑非expr1 -a expr2逻辑与expr1 -o expr2逻辑或2.3 多条件分支实现对于需要多个条件判断的场景可以使用elif结构if [ condition1 ]; then # 条件1为真时执行 elif [ condition2 ]; then # 条件2为真时执行 else # 所有条件都不满足时执行 fi一个根据系统负载采取不同措施的示例load$(uptime | awk {print $(NF-2)} | tr -d ,) if [ $(echo $load 2.0 | bc) -eq 1 ]; then echo 高负载警告当前负载$load # 发送告警邮件等操作 elif [ $(echo $load 1.0 | bc) -eq 1 ]; then echo 中等负载$load else echo 负载正常$load fi3. 条件语句中的常见陷阱与解决方案3.1 变量未引用的空值问题这是Shell脚本中最常见的错误之一。当变量可能为空时必须用双引号包裹# 错误示范 if [ $var value ]; then # 如果$var为空会变成 [ value ] 导致语法错误 # 正确做法 if [ $var value ]; then3.2 字符串与数值比较混淆Shell中字符串比较使用数值比较使用-eq混用会导致意外结果a05 b5 # 字符串比较按字典序 if [ $a $b ]; then # 结果为假 # 数值比较 if [ $a -eq $b ]; then # 结果为真3.3 复合条件判断的优先级问题当使用-a(与)和-o(或)组合多个条件时要注意Shell的运算符优先级# 这个判断可能不符合预期 if [ $a yes -o $b yes -a $c yes ]; then # 明确使用括号分组需要转义 if [ $a yes -o \( $b yes -a $c yes \) ]; then # 更清晰的做法是使用多个[]和Shell的、|| if [ $a yes ] || { [ $b yes ] [ $c yes ]; }; then3.4 浮点数比较的特殊处理Shell的test命令不支持浮点数比较需要借助外部工具如bcnum13.14 num22.71 # 错误做法会报错 if [ $num1 -gt $num2 ]; then # 正确做法 if [ $(echo $num1 $num2 | bc) -eq 1 ]; then4. 高级条件判断技巧4.1 使用双括号和双方括号现代Shell如Bash提供了更强大的(( ))和[[ ]]语法双括号(( ))用于算术运算和比较if (( a b )); then # 不需要$前缀和引号 echo a大于b fi双方括号[[ ]]增强的字符串比较支持正则匹配if [[ $filename *.log ]]; then echo 这是一个日志文件 fi # 正则匹配 if [[ $var ~ ^[0-9]$ ]]; then echo var是纯数字 fi4.2 case语句多分支选择对于基于模式匹配的多分支选择case语句比多个if-elif更清晰case $1 in start) echo 启动服务 ;; stop) echo 停止服务 ;; restart|reload) echo 重启服务 ;; *) echo 用法$0 {start|stop|restart} exit 1 esac4.3 命令返回值直接判断由于Shell条件本质是检查命令返回值可以直接判断命令是否成功if grep -q error /var/log/syslog; then echo 系统日志中包含错误信息 fi # 检查命令是否可用 if command -v python3 /dev/null 21; then echo Python3已安装 else echo Python3未找到 fi5. 实战案例系统健康检查脚本结合前面所学我们实现一个实用的系统健康检查脚本#!/bin/bash # 检查根分区使用率 root_usage$(df -h / | awk NR2 {print $5} | tr -d %) if [ $root_usage -gt 90 ]; then echo [紧急] 根分区使用率超过90%当前${root_usage}% elif [ $root_usage -gt 70 ]; then echo [警告] 根分区使用率超过70%当前${root_usage}% else echo [正常] 根分区使用率${root_usage}% fi # 检查内存使用 free_mem$(free -m | awk /Mem:/ {print $4}) if [ $free_mem -lt 100 ]; then echo [警告] 可用内存不足100MB fi # 检查SWAP使用 swap_used$(free | awk /Swap:/ {print $3}) if [ $swap_used -ne 0 ]; then echo [注意] SWAP空间正在使用中 fi # 检查关键进程 processes(sshd nginx mysqld) for proc in ${processes[]}; do if ! pgrep -x $proc /dev/null; then echo [错误] 进程 $proc 未运行 fi done # 根据条件执行不同操作 if [ -f /tmp/emergency_maintenance ]; then echo 检测到维护标志文件跳过详细检查 elif [ $(date %H) -ge 22 ] || [ $(date %H) -lt 6 ]; then echo 夜间时段执行精简检查 else echo 日间时段执行完整检查 # 添加更多检查项... fi这个脚本展示了条件语句在实际系统管理中的应用包括数值比较分区使用率文件存在性检查维护标志文件时间条件判断不同时段执行不同检查进程状态检查多级告警紧急/警告/正常6. 调试与优化技巧6.1 调试模式下的条件语句检查使用set -x开启调试模式可以看到条件判断的实际执行过程#!/bin/bash set -x sampletest if [ -n $sample ]; then echo 变量非空 fi set x输出会显示实际执行的命令 sampletest [ -n test ] echo 变量非空 变量非空 set x6.2 复杂条件的分解测试对于复杂的条件组合可以分步测试每个子条件cond1[ -f /etc/passwd ] cond2[ $USER root ] echo cond1结果$($cond1; echo $?) echo cond2结果$($cond2; echo $?) if $cond1 $cond2; then echo 所有条件满足 fi6.3 性能优化建议减少子Shell调用$(command)会创建子Shell在循环中频繁使用会影响性能使用内置测试[ ]是外部命令[[ ]]是Shell内置后者更快提前终止判断将最可能失败的条件放在前面缓存命令结果重复使用的命令结果保存到变量6.4 可读性提升技巧为复杂条件添加注释使用有意义的变量名存储条件过长的条件可以分行书写if [[ $response yes ]] \ || [[ $force_flag true ]] \ [[ $dry_run ! true ]]; then # 执行操作 fiShell条件语句看似简单但要写出健壮、可靠的判断逻辑需要深入理解其工作原理并积累实践经验。我在实际工作中发现90%的Shell脚本错误都源于条件判断不当特别是在边界条件和异常情况处理方面。掌握这些技巧后你的Shell脚本将更加稳定可靠。