Shell编程之条件语句

目录

一、条件测试操作

1. 文件测试:系统资源的 “身份验证”

核心选项与应用场景

实战案例:智能创建数据备份目录

2. 整数值比较:数字世界的逻辑推演

比较运算符详解

案例:服务器负载监控脚本

3. 字符串比较:文本处理的精准匹配

核心运算符与使用规范

案例:用户输入合法性校验

4. 逻辑测试:复杂条件的组合艺术

逻辑运算符对比与示例

案例:多条件组合的环境检测

二、if 条件语句:流程控制的核心引擎

1. 单分支 if:条件成立时的专属执行路径

实战:静默清理临时文件(仅当文件存在时)

2. 双分支 if:两种场景的明确分野

典型应用:网络连通性检测脚本

3. 多分支 if:多层筛选的逻辑漏斗

案例:学生成绩分级系统(支持百分制与等级制)

4. if 语句最佳实践

三、case 分支语句:多选项匹配的高效解决方案

1. 语法结构与执行流程

模式匹配规则

2. 实战案例:字符类型检测工具

3. 生产级实践:系统服务控制脚本

4. case vs if:场景选择指南

四、常见错误与避坑指南

1. 空格引发的语法错误

2. 数值比较与字符串比较混淆

3. case 模式匹配的引号缺失

4. 状态码理解误区


一、条件测试操作

Shell 脚本的 “智能” 源于对系统状态的精准判断,而条件测试正是实现这一能力的基础。通过test命令或简化的[条件表达式]形式,脚本能够对文件属性、数值关系、字符串内容及多重条件组合进行检测,为流程控制提供决策依据。

1. 文件测试:系统资源的 “身份验证”

文件测试是 Shell 脚本中最基础的检测手段,用于判断文件或目录的类型、存在性及权限属性。其核心选项遵循简洁的英文缩写规则,配合路径参数即可完成检测。

核心选项与应用场景

选项功能描述语法示例返回值说明
-d检测是否为目录[ -d /var/log ]0(是目录)/1(否)
-e检测文件 / 目录是否存在[ -e /etc/hosts ]0(存在)/1(不存在)
-f检测是否为普通文件[ -f /usr/bin/bash ]0(是文件)/1(否)
-r检测当前用户是否可读[ -r ~/secret.txt ]0(可读)/1(不可读)
-w检测当前用户是否可写[ -w ~/test.txt ]0(可写)/1(不可写)
-x检测是否可执行[ -x /usr/sbin/nginx ]0(可执行)/1(不可执行)

实战案例:智能创建数据备份目录

#!/bin/bash
# 脚本:create_backup_dir.sh
backup_dir="/data/backup"
# 检测目录是否存在,不存在则递归创建并设置权限
if [ ! -d "$backup_dir" ]; then
  mkdir -p "$backup_dir"
  chmod 755 "$backup_dir"
  echo "备份目录已创建:$backup_dir"
fi
  • 逻辑解析! -d表示 “非目录”,结合mkdir -p确保目录存在,chmod设置安全权限,保障脚本健壮性。

2. 整数值比较:数字世界的逻辑推演

整数值比较用于判断两个整数的大小关系,常见于资源监控、阈值告警等场景。需注意运算符的英文缩写含义及与字符串比较的区别。

比较运算符详解

运算符含义语法示例成立条件
-eq等于(Equal)[ $a -eq $b ]\(a与\)b 数值相等
-ne不等于(Not Equal)[ $a -ne $b ]\(a与\)b 数值不等
-gt大于(Greater Than)[ $a -gt $b ]\(a大于\)b
-lt小于(Lesser Than)[ $a -lt $b ]\(a小于\)b
-le小于等于[ $a -le $b ]\(a≤\)b
-ge大于等于[ $a -ge $b ]\(a≥\)b

案例:服务器负载监控脚本

#!/bin/bash
# 脚本:load_monitor.sh
current_load=$(uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | tr -d ' ')
# 判断1分钟负载是否超过CPU核心数(假设4核)
if [ $(echo "$current_load > 4" | bc) -eq 1 ]; then
  echo "警告:1分钟负载达$current_load,超过4核阈值!"
  # 此处可添加邮件告警或自动扩容逻辑
fi
  • 数据处理:通过uptime获取负载信息,利用bc命令实现浮点数值比较,突破传统整数比较限制。

3. 字符串比较:文本处理的精准匹配

字符串比较用于检测文本内容是否符合预期,需注意引号的使用(避免空值导致语法错误)和运算符的正确选择。

核心运算符与使用规范

运算符功能语法示例成立条件
=等于[ "$str1" = "$str2" ]字符串内容完全相同(区分大小写)
!=不等于[ "$str1" != "$str2" ]字符串内容不同
-z为空[ -z "$str" ]字符串长度为 0(空值或未定义)
-n非空[ -n "$str" ]字符串长度大于 0

案例:用户输入合法性校验

#!/bin/bash
# 脚本:input_validate.sh
read -p "请输入管理员密码:" -s password
if [ -z "$password" ]; then
  echo -e "\n错误:密码不可为空!"
  exit 1
elif [ ${#password} -lt 8 ]; then
  echo -e "\n错误:密码长度需至少8位!"
  exit 1
else
  echo -e "\n密码校验通过,正在登录..."
  # 此处可添加密码哈希校验逻辑
fi
  • 多层校验:先判断是否为空,再检查长度,结合-s选项隐藏输入内容,提升安全性。

4. 逻辑测试:复杂条件的组合艺术

逻辑测试通过 “与”“或”“非” 操作组合多个条件,实现复杂场景的判断。需区分命令行符号(&&/||)与test专用选项(-a/-o/!)的使用场景。

逻辑运算符对比与示例:

类型

符号

功能

语法示例(等价写法)

成立条件

逻辑与

&&

前后条件均成立

[ $a -gt 10 ] && [ $b -lt 20 ]

[ $a -gt 10 -a $b -lt 20 ]

两者同时为真

逻辑或

||

至少一个成立

[ -e /data/file.txt ] || [ -w /data ] 

至少一个为真

逻辑非

!

条件取反

![ -f file.txt ]

条件不成立

案例:多条件组合的环境检测

#!/bash
# 脚本:env_check.sh
# 检测当前用户是否为root且系统版本为CentOS 7
if [ "$(whoami)" = "root" ] && [ "$(lsb_release -rs)" = "7.9" ]; then
  echo "环境符合要求,开始部署..."
else
  echo "错误:需以root用户在CentOS 7.9环境执行!"
  exit 1
fi
  • 条件组合:通过whoamilsb_release获取动态信息,&&确保两个条件同时满足,保障脚本执行环境的正确性。

二、if 条件语句:流程控制的核心引擎

当脚本需要根据条件执行多行命令或复杂逻辑时,if语句凭借清晰的分支结构成为首选。根据业务逻辑的复杂度,可分为单分支、双分支和多分支三种形式。

1. 单分支 if:条件成立时的专属执行路径

语法结构

if 条件测试
then
  命令序列  # 条件成立时执行
fi

执行逻辑

  1. 执行条件测试,获取返回值$?
  2. 若返回 0(条件成立),执行then后的命令序列;
  3. 否则跳过then块,继续执行后续代码。

实战:静默清理临时文件(仅当文件存在时)

#!/bash
# 脚本:clean_temp_files.sh
temp_file="/tmp/temp.log"
if [ -f "$temp_file" ]; then
  rm -f "$temp_file"
  echo "临时文件已清理:$temp_file"
fi
  • 安全机制:通过-f确保仅删除存在的文件,避免rm命令因文件不存在报错,提升脚本容错性。

2. 双分支 if:两种场景的明确分野

语法结构

if 条件测试
then
  命令序列1  # 条件成立时执行
else
  命令序列2  # 条件不成立时执行
fi

典型应用:网络连通性检测脚本

#!/bash
# 脚本:network_check.sh
target="www.baidu.com"
ping -c 3 -W 5 "$target" &>/dev/null
if [ $? -eq 0 ]; then
  echo "网络连通正常,目标地址:$target"
else
  echo "网络连接失败,尝试重启网络服务..."
  systemctl restart network
fi
  • 输出控制&>/dev/null屏蔽ping命令的冗余输出,systemctl实现故障自愈,增强脚本实用性。

3. 多分支 if:多层筛选的逻辑漏斗

语法结构

if 条件测试1
then
  命令序列1
elif 条件测试2
then
  命令序列2
...
else
  命令序列n  # 所有条件不成立时执行
fi

案例:学生成绩分级系统(支持百分制与等级制)

#!/bash
# 脚本:score_grading.sh
read -p "请输入成绩(0-100):" score
if [ $score -ge 90 ]; then
  grade="A(优秀)"
elif [ $score -ge 80 ]; then
  grade="B(良好)"
elif [ $score -ge 70 ]; then
  grade="C(中等)"
elif [ $score -ge 60 ]; then
  grade="D(及格)"
else
  grade="F(不及格)"
fi
echo "成绩$score对应等级:$grade"
  • 逻辑顺序:从最高条件开始判断(如-ge 90),避免低优先级条件被覆盖,确保分级逻辑的正确性。

4. if 语句最佳实践

  • 引号规范:变量引用必须加双引号(如"$var"),防止空值导致语法错误(如[ $var -eq 10 ]$var为空时引发解析错误);
  • 错误处理:在else分支添加明确的错误提示和退出码(如exit 1),便于上层脚本检测异常;
  • 嵌套优化:避免超过 3 层嵌套,复杂逻辑可拆分为独立函数或使用case语句,保持代码可读性。

三、case 分支语句:多选项匹配的高效解决方案

当变量存在固定取值(如命令参数、用户菜单选项)时,case语句通过模式匹配实现更简洁的多分支控制,避免多层if-elif的繁琐判断,提升代码的可维护性。

1. 语法结构与执行流程

语法格式

case 变量值 in
  模式1)
    命令序列1
    ;;
  模式2)
    命令序列2
    ;;
  *)  # 默认模式(通配所有未匹配值)
    命令序列n
    ;;
esac

执行逻辑

  1. 将 “变量值” 依次与 “模式 1”“模式 2”… 进行匹配;
  2. 匹配成功则执行对应命令序列,遇到;;跳转至esac结束;
  3. 所有模式不匹配时执行默认模式*

模式匹配规则

  • 精确匹配:直接使用字符串(如start)匹配变量值为start);
  • 范围匹配[a-z]匹配小写字母,[0-9]匹配单个数字;
  • 或操作start|stop)匹配startstop
  • 通配符*匹配任意字符(包括空值),?匹配单个字符。

2. 实战案例:字符类型检测工具

#!/bash
# 脚本:char_type_detector.sh
read -p "请输入一个字符:" -n 1 char  # 读取单个字符
echo -e "\n您输入的字符是:$char"
case "$char" in
  [a-zA-Z])  # 匹配大小写字母
    echo "类型:字母(ASCII码:$(printf "%d" "'$char'))"
    ;;
  [0-9])  # 匹配数字
    echo "类型:数字(数值:$char)"
    ;;
  [[:space:]])  # 匹配空格、制表符等空白字符
    echo "类型:空白字符"
    ;;
  *)  # 特殊字符(如!@#$%等)
    echo "类型:特殊字符(ASCII码:$(printf "%d" "'$char'))"
    ;;
esac
  • 高级特性:使用-n 1读取单个字符,printf "%d" "'$char'"获取 ASCII 码,结合[[:space:]]匹配所有空白字符,提升检测精度。

3. 生产级实践:系统服务控制脚本

#!/bash
# 脚本:service_manager.sh
service_name="httpd"
case "$1" in
  start)
    echo -n "启动$service_name服务..."
    systemctl start "$service_name"
    if [ $? -eq 0 ]; then
      echo "成功"
    else
      echo "失败"
      exit 1
    fi
    ;;
  stop)
    echo -n "停止$service_name服务..."
    systemctl stop "$service_name"
    echo "成功"
    ;;
  restart)
    "$0" stop  # 调用当前脚本的stop功能
    "$0" start  # 调用当前脚本的start功能
    ;;
  status)
    status=$(systemctl is-active "$service_name")
    echo "$service_name服务状态:$status"
    ;;
  *)  # 处理未知参数
    echo "用法:$0 {start|stop|restart|status}"
    exit 1
    ;;
esac
  • 脚本自调用:通过"$0"引用脚本自身路径,restart分支实现 “先停止后启动” 的原子操作;
  • 状态查询systemctl is-active直接返回服务状态(active/inactive),比通过$?判断更直观。

4. case vs if:场景选择指南

场景特征case 优势if 优势
固定取值判断(如命令参数)模式匹配简洁,结构清晰动态条件组合(如文件权限 + 数值范围)
多选项菜单驱动选项对应明确,易于扩展非固定值复杂逻辑(如字符串包含判断)
输入类型分类(如字母 / 数字)范围匹配高效跨类型条件组合(如文件存在且用户可读)

四、常见错误与避坑指南

1. 空格引发的语法错误

  • 错误示例[ $a -eq $b ](缺少空格导致解析错误)
  • 正确写法[ "$a" -eq "$b" ](确保[/]与表达式间有空格,变量加引号)

2. 数值比较与字符串比较混淆

  • 错误场景:使用=进行数值判断(如[ $a = 10 ]实际执行字符串匹配)
  • 解决方案:数值比较用-eq等专用运算符,字符串比较用=,严格区分数据类型。

3. case 模式匹配的引号缺失

  • 错误示例case $var in start) ... ;;(未加引号,变量为空时匹配失败)
  • 最佳实践:始终为变量添加双引号("$var"),确保空值或含空格的字符串正确匹配。

4. 状态码理解误区

  • 错误逻辑:认为$?=0仅表示 “条件成立”,实际是 “前一命令执行成功”
  • 正确认知:条件测试的返回值与命令执行状态码一致,需结合具体命令(如test/[ ]/ 实际服务命令)判断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值