当前位置: 首页 > news >正文

13.Shell脚本修炼手册---玩转 CASE 语句(应用场景与实践技巧)

case 条件语句的应用实践

文章目录

    • case 条件语句的应用实践
      • case 条件语句的核心逻辑与语法
        • 核心逻辑
        • 语法格式
        • 生活化举例
      • 基础实践:判断用户输入的数字(1-3)
        • 实验流程
        • 脚本实现
        • 执行验证
      • 实践:给输出字符串添加颜色
        • 实验流程
        • 脚本实现
        • 执行验证
      • 企业级案例:用 case 管理系统服务
        • 案例 1:控制 sshd 服务(启停 / 重启 / 状态查询)
          • 实验流程
          • 脚本实现(简化版)
          • 执行验证
        • 案例 2:用户管理脚本(添加 / 删除 / 查询用户)
          • 需求说明
          • 实验流程
          • 脚本实现
          • 执行验证
      • 综合实验:批量配置 IP 地址和主机名
        • 需求说明
        • 实验流程
        • 脚本实现
        • 执行验证
      • 本章小结

在 Shell 编程中,我们经常需要根据不同的条件执行不同的操作。比如判断用户输入的指令是 “start” 还是 “stop”,再执行对应的服务启停操作。这时除了用if/elif/else多分支语句,case条件语句会是更合适的选择 —— 它的结构更工整,逻辑更清晰,尤其适合处理固定值的多分支判断场景,在系统服务脚本等企业级场景中非常常用。

case 条件语句的核心逻辑与语法

核心逻辑

case语句的工作方式就像 “对号入座”:
程序会拿一个变量的值,逐个与预设的 “标签”(值 1、值 2、值 3…)比对。

  • 一旦找到匹配的标签,就执行该标签后的指令,直到遇到;;(相当于 “结束当前分支”),然后跳出整个case语句;
  • 如果所有标签都不匹配,就执行*)后的指令(相当于 “其他情况”),这部分可以理解为if语句中的else
  • 标签部分还支持用|表示 “或”(比如start|begin表示匹配 “start” 或 “begin”)。
语法格式
case "变量值" in标签1)  # 当变量值等于"标签1"时指令1  # 执行的操作(可以是多行命令);;     # 结束当前分支标签2|标签3)  # 变量值等于"标签2"或"标签3"时指令2;;*)  # 所有标签都不匹配时指令3  # 默认操作(通常是提示信息);;  # 此处的;;可以省略,但建议保留以保持格式统一
esac  # case的反写,表示语句结束
生活化举例

用一个更形象的例子理解case逻辑:

case "用户的考试分数" in90-100)  # 分数在90到100之间echo "优秀";;60-89)   # 分数在60到89之间echo "及格";;0-59)    # 分数在0到59之间echo "不及格";;*)       # 其他情况(比如输入非数字)echo "请输入有效的分数";;
esac

基础实践:判断用户输入的数字(1-3)

实验流程
  1. 创建脚本文件,通过read命令获取用户输入的数字;
  2. case语句判断数字是否为 1、2、3,分别输出对应信息;
  3. 若输入其他数字,提示 “请输入 1-3 之间的数字”;
  4. 执行脚本,验证不同输入的结果。
脚本实现
#!/bin/bash
# 提示用户输入1-3之间的数字,并将输入保存到变量num中
read -p "请输入一个1-3之间数字:" num# 用case判断num的值
case $num in1)  # 若num等于1echo "您输入的数字是:$num"  # 输出提示;;  # 结束当前分支2)  # 若num等于2echo "您输入的数字是:$num";;3)  # 若num等于3echo "您输入的数字是:$num";;*)  # 若num是其他值echo "请输入一个1-3之间数字。"  # 提示输入错误;;
esac
执行验证
# 输入1(符合条件)
[bq@shell ~]$ bash case1.sh 
请输入一个1-3之间数字:1
您输入的数字是:1# 输入4(不符合条件)
[bq@shell ~]$ bash case1.sh 
请输入一个1-3之间数字:4
请输入一个1-3之间数字。# 输入字母(不符合条件)
[bq@shell ~]$ bash case1.sh 
请输入一个1-3之间数字:a
请输入一个1-3之间数字。

实践:给输出字符串添加颜色

实验流程
  1. 创建脚本,接收参数(PASS/FAIL/DONE);
  2. case语句根据参数,通过 ANSI 转义字符输出对应颜色的文字(绿色 PASS、红色 FAIL、紫色 DONE);
  3. 若参数错误,提示正确用法;
  4. 执行脚本,验证颜色输出效果。
脚本实现
#!/bin/bash
# 根据传入的参数($1)输出带颜色的文字
case $1 inPASS)# \033[1;32m:设置文字为高亮绿色;\033[0;39m:恢复默认颜色echo -e '\033[1;32mPASS\033[0;39m';;FAIL)# \033[1;31m:设置文字为高亮红色echo -e '\033[1;31mFAIL\033[0;39m';;DONE)# \033[1;35m:设置文字为高亮紫色echo -e '\033[1;35mDONE\033[0;39m';;*)# 若参数不是PASS/FAIL/DONE,提示用法echo "Usage: $0 PASS|FAIL|DONE";;
esac
执行验证
# 输出绿色PASS
[bq@shell ~]$ bash case2.sh PASS
PASS  # 实际显示为绿色高亮# 输出红色FAIL
[bq@shell ~]$ bash case2.sh FAIL
FAIL  # 实际显示为红色高亮# 输出紫色DONE
[bq@shell ~]$ bash case2.sh DONE
DONE  # 实际显示为紫色高亮# 参数错误时提示用法
[bq@shell ~]$ bash case2.sh ABC
Usage: case2.sh PASS|FAIL|DONE

企业级案例:用 case 管理系统服务

案例 1:控制 sshd 服务(启停 / 重启 / 状态查询)
实验流程
  1. 创建脚本,接收参数(start/stop/restart/reload/status);
  2. case语句根据参数调用systemctl命令操作 sshd 服务;
  3. 若参数错误,提示正确用法;
  4. 执行脚本,验证服务操作是否生效。
脚本实现(简化版)
#!/bin/bash 
# 根据传入的参数($1)管理sshd服务
case $1 in # 匹配start/stop/restart/reload/status中的任意一个参数start | stop | restart | reload | status)# 直接用参数作为systemctl的操作指令(例如$1为start时,执行systemctl start sshd)systemctl $1 sshd;;*)# 参数错误时,提示用法echo "Usage: case-ssh start|stop|restart|reload|status";;
esac 
执行验证
# 启动sshd服务
[root@shell ~]# bash case-ssh start
# 查看服务状态(应显示"active (running)")
[root@shell ~]# bash case-ssh status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: active (running) since ...# 停止sshd服务
[root@shell ~]# bash case-ssh stop
# 再次查看状态(应显示"inactive (dead)")
[root@shell ~]# bash case-ssh status
● sshd.service - OpenSSH server daemonLoaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)Active: inactive (dead) since ...
案例 2:用户管理脚本(添加 / 删除 / 查询用户)
需求说明

通过脚本user-mgr管理/etc/users文件中的用户清单,支持:

  • 添加用户(参数-add|-a):若用户已存在则提示,否则写入文件;
  • 删除用户(参数-del|-d):若用户不存在则提示,否则从文件中删除;
  • 查询用户(参数-search|-s):判断用户是否在文件中;
  • 限制仅 root 用户执行,且必须传入 2 个参数(操作 + 用户名)。
实验流程
  1. 创建脚本,先判断执行权限(是否为 root)和参数数量(是否为 2 个);
  2. 定义函数实现用户查询、添加、删除逻辑(用grep检查存在性,sed删除行,chattr锁定文件防止误改);
  3. case语句根据参数调用对应函数;
  4. 执行脚本,验证添加、查询、删除功能。
脚本实现
#!/bin/bash# 检查是否为root用户(非root则提示并退出)
[ $UID -ne 0 ] && echo '请使用root用户执行' && exit 1# 定义用户清单文件路径
users_info_file=/etc/users
# 若文件不存在则创建
[ -f ${users_info_file} ] || touch ${users_info_file}# 定义用法提示函数
function usage () {echo "Usage: user-mgr [ [-add|-a ] | [ -d|-del ] | [ -s|-search ] ] username" exit 2
}# 定义用户查询函数(参数:用户名)
function search_user () {# 用grep静默查询文件中是否存在"username: 用户名"(-q:不输出结果,仅返回状态)if grep -q "username: $1" ${users_info_file};thenecho "$1 已存在"return 0  # 存在则返回0(成功状态)elseecho "$1 不存在"return 1  # 不存在则返回1(失败状态)fi
}# 定义用户添加函数(参数:用户名)
function add_user () {# 先调用查询函数,若用户已存在($?为0)则提示search_user $1 &>/dev/null  # &>/dev/null:忽略查询函数的输出if [ $? -eq 0 ];thenecho "$1 已存在,无法重复添加"elsechattr -i ${users_info_file}  # 解除文件锁定(-i:移除不可修改属性)# 向文件追加用户信息,并提示成功echo "username: $1" >> ${users_info_file} && echo "添加用户 $1 成功"chattr +i ${users_info_file}  # 重新锁定文件(+i:设置不可修改属性)fi
}# 定义用户删除函数(参数:用户名)
function del_user () {# 先调用查询函数,若用户不存在($?为1)则提示search_user $1 &>/dev/nullif [ $? -eq 1 ];thenecho "$1 不存在,无法删除"elsechattr -i ${users_info_file}  # 解除文件锁定# 用sed删除包含"username: 用户名"的行,并提示成功sed -i "/username: $1/d" ${users_info_file} && echo "删除用户 $1 成功"chattr +i ${users_info_file}  # 重新锁定文件fi
}# 检查参数数量(若不是2个则调用用法提示)
[ $# -ne 2 ] && usage# 根据第一个参数(操作类型)调用对应函数
case $1 in-a|-add)shift  # 移除第一个参数(保留用户名作为后续函数的参数)add_user $1;;-d|-del)shiftdel_user $1;;-s|-search)shiftsearch_user $1;;*)usage  # 参数不匹配时提示用法;;
esac
执行验证
# 初始状态:/etc/users为空
[root@shell ~]# cat /etc/users# 查询不存在的用户(bq)
[root@shell ~]# bash user-mgr -s bq
bq 不存在# 添加用户bq
[root@shell ~]# bash user-mgr -a bq
添加用户 bq 成功# 再次查询bq(已存在)
[root@shell ~]# bash user-mgr -s bq
bq 已存在# 查看用户文件(已写入)
[root@shell ~]# cat /etc/users 
username: bq# 重复添加bq(提示已存在)
[root@shell ~]# bash user-mgr -a bq
bq 已存在,无法重复添加# 删除用户bq
[root@shell ~]# bash user-mgr -d bq
删除用户 bq 成功# 再次删除bq(提示不存在)
[root@shell ~]# bash user-mgr -d bq
bq 不存在,无法删除# 非root用户执行(提示权限不足)
[bq@shell ~]$ bash user-mgr -s bq
请使用root用户执行

综合实验:批量配置 IP 地址和主机名

需求说明

根据输入的数字(21-34),自动配置服务器的 IP 地址和主机名,对应关系如下:

输入参数IP 地址主机名
2110.1.8.21ha1.market.com
2210.1.8.22ha2.market.com
2310.1.8.23proxy1.market.com
2410.1.8.24proxy2.market.com
2510.1.8.25company1.market.com
2610.1.8.26company2.market.com
2710.1.8.27shop1.market.com
2810.1.8.28shop2.market.com
2910.1.8.29db1.market.com
3010.1.8.30db2.market.com
3110.1.8.31storage.market.com
3210.1.8.32backup.market.com
3310.1.8.33network.market.com
3410.1.8.34client.market.com
  1. 实验流程
    1. 创建脚本,接收一个参数(21-34);
    2. 定义函数set_ip:根据参数设置 IP 地址(通过nmcli命令);
    3. 定义函数set_hostname:用case语句根据参数匹配对应的主机名,通过hostnamectl设置;
    4. 主函数调用上述两个函数,执行配置;
    5. 执行脚本后,用ip addrhostname命令验证结果。
    脚本实现
    #!/bin/bash# 定义网络接口名称(根据实际环境修改,如ens33、eth0等)
    interface=ens33# 定义域名后缀
    domain=market.com# 用法提示函数(若参数不符合要求则调用)
    usage (){echo "Usage: $0 21-34"  # 提示参数必须是21到34之间的数字exit 1
    }# 设置IP地址的函数(参数:数字21-34)
    function set_ip () {if [ $# -eq 0 ]; then  # 若未传参数,提示用法usage   else# 用nmcli修改接口的IP地址(格式:10.1.8.参数/24)nmcli connection modify $interface ipv4.address 10.1.8.$1/24# 重新启用接口使配置生效nmcli connection up $interfaceecho "IP地址已设置为 10.1.8.$1/24"fi
    }# 设置主机名的函数(参数:数字21-34)
    function set_hostname () {# 根据参数匹配对应的主机名case $1 in21|22)  # 21或22:主机名前缀为ha,序号=参数-20HOSTNAME=ha$(( $1 - 20 )).$domain;;23|24)  # 23或24:前缀为proxy,序号=参数-22HOSTNAME=proxy$(( $1 - 22 )).$domain;;25|26)  # 25或26:前缀为company,序号=参数-24HOSTNAME=company$(( $1 - 24 )).$domain;;27|28)  # 27或28:前缀为shop,序号=参数-26HOSTNAME=shop$(( $1 - 26 )).$domain;;29|30)  # 29或30:前缀为db,序号=参数-28HOSTNAME=db$(( $1 - 28 )).$domain;;31)     # 31:固定主机名storageHOSTNAME=storage.$domain;;32)     # 32:固定主机名backupHOSTNAME=backup.$domain;;33)     # 33:固定主机名networkHOSTNAME=network.$domain;;34)     # 34:固定主机名clientHOSTNAME=client.$domain;;*)      # 其他参数:提示用法usage;;esac# 设置主机名hostnamectl set-hostname $HOSTNAMEecho "主机名已设置为 $HOSTNAME"
    }# 主函数:调用IP和主机名设置函数
    function main() {set_ip $1set_hostname $1
    }# 执行主函数(传入脚本接收的参数)
    main $*
    
    执行验证
    # 以参数21为例执行脚本
    [root@shell ~]# bash set_network.sh 21
    IP地址已设置为 10.1.8.21/24
    主机名已设置为 ha1.market.com# 验证IP地址(ens33接口应显示10.1.8.21)
    [root@shell ~]# ip addr show ens33
    ...
    inet 10.1.8.21/24 brd 10.1.8.255 scope global noprefixroute ens33
    ...# 验证主机名(应显示ha1.market.com)
    [root@shell ~]# hostname
    ha1.market.com# 测试参数34(验证IP和主机名)
    [root@shell ~]# bash set_network.sh 34
    IP地址已设置为 10.1.8.34/24
    主机名已设置为 client.market.com[root@shell ~]# ip addr show ens33 | grep inet
    inet 10.1.8.34/24 brd 10.1.8.255 scope global noprefixroute ens33[root@shell ~]# hostname
    client.market.com
    

本章小结

  1. case 语句的适用场景
    当需要判断的变量值是固定的字符串或数字(如 start/stop、1-34 等)时,用caseif/elif/else更简洁易读,尤其适合编写服务管理脚本(如启停脚本)。
  2. 与 if 语句的区别
    • case:适合处理固定值的多分支判断,结构工整,逻辑清晰;
    • if:适合处理条件表达式判断(如数值大小、文件属性等),应用范围更广(几乎所有case都能用if实现,但反之不成立)。
  3. 核心语法要点
    • in引出标签列表,标签间用|表示 “或”;
    • 每个分支用;;结束,默认分支用*)表示;
    • 语句以esac(case 反写)结束。

如涉及版权问题请联系作者处理!!

http://www.dtcms.com/a/347706.html

相关文章:

  • GitHub Actions workflow最佳实践
  • 提问:温度不改变 logits 与概率的排名,为何还会影响模型输出?
  • Linux 进程间通信之System V 共享内存
  • 深入探讨集成学习:Bagging与Boosting的核心原理与实践
  • RAG系统开发中的12大痛点及应对策略
  • SVG.js 一个轻量且强大的图形库
  • Sql server的行转列
  • word——表格跨页显示表头
  • PCL点云库入门(第24讲)——PCL库点云特征之NARF特征描述 Normal Aligned Radial Feature(NARF)
  • VGG改进(4):融合Linear Attention的高效CNN设计与实践
  • 遥感机器学习入门实战教程|Sklearn案例⑧:评估指标(metrics)全解析
  • 机器学习案例——预测矿物类型(数据处理部分)
  • 如何在wsl2+Ubuntu中安装Eclipse
  • 第七章 利用Direct3D绘制几何体
  • 一个简洁的 C++ 日志模块实现
  • AI + 医疗:智能诊断如何突破技术瓶颈,走进基层医院?
  • Azure Kubernetes Service (AKS)
  • 在Linux环境中为Jupyter Lab安装Node.js环境
  • `sudo apt update` 总是失败
  • 【KO】前端面试六
  • X射线胸部肺炎检测:基于深度学习的医学影像分析项目
  • Trae Solo模式生成一个旅行足迹App
  • JS事件的概念
  • 【最后203篇系列】035 数据表同步简单方案
  • 深入理解 React useEffect
  • 语义普遍性与形式化:构建深层语义理解的统一框架
  • 串与数组:从字符处理到多维存储的数据结构详解
  • 【python】min(key=...)用法
  • 【Kubernetes知识点】资源配额与访问控制
  • 小白向:Obsidian(Markdown语法学习)快速入门完全指南:从零开始构建你的第二大脑(免费好用的笔记软件的知识管理系统)、黑曜石笔记