Shell case ... esac
《Shell case ... esac 分支语句》深度学习版 🧠
🎉 欢迎来到 Shell 编程中非常实用的一章 —— case 分支结构。它是 if 的一种更简洁、清晰的替代方式,特别适合处理多个固定值匹配的情况(如用户输入、命令参数、状态码等)。掌握它,你就能写出更加优雅、可读性强的脚本!
🎯 学习目标
- 理解
case ... esac的基本语法与执行流程 - 掌握如何用
case实现多条件分支判断 - 能在实际脚本中灵活使用通配符、正则匹配、模式匹配等技巧
- 学会结合命令行参数解析、菜单选择等常见应用场景
- 避免常见陷阱和语法错误,写出健壮可靠的 Shell 条件分支语句
⭐ 核心重点(知识点速览)
| 类型 | 内容 | 描述 |
|---|---|---|
| 基本语法 | case value in pattern) ... ;; esac |
多分支匹配结构 |
| 匹配方式 | 字符串、通配符、正则 | 支持 *, ?, [0-9] 等 |
| 结束关键字 | ;; |
每个分支必须以 ;; 结尾 |
| 默认分支 | *) |
类似 switch 中的 default |
| 常见用途 | 参数解析、菜单系统、状态处理 | 提高代码可读性 |
| 不同 shell 差异 | bash vs dash | 注意兼容性问题 |
📖 详细讲解
一、基本语法结构
case $variable in
pattern1)
# 匹配 pattern1 时执行的代码
;;
pattern2)
# 匹配 pattern2 时执行的代码
;;
*)
# 默认情况下的代码
;;
esac
💡
esac是case的反向拼写,表示结束。
二、简单示例:根据用户输入执行不同操作 ✅
read -p "请输入你的操作系统(windows/linux/mac):" os
case "$os" in
windows)
echo "👋 欢迎 Windows 用户!"
;;
linux)
echo "🐧 欢迎 Linux 用户!"
;;
mac)
echo "🍎 欢迎 macOS 用户!"
;;
*)
echo "❌ 输入无效,请输入 windows、linux 或 mac"
;;
esac
三、通配符匹配(Wildcard Matching)🔍
case 支持使用通配符进行模糊匹配:
| 通配符 | 含义 |
|---|---|
* |
匹配任意长度字符串 |
? |
匹配单个字符 |
[abc] |
匹配 a、b 或 c |
[a-z] |
匹配小写字母 |
| ` | ` |
✅ 示例:匹配数字范围或前缀
read -p "请输入一个等级(A/B/C/其他):" grade
case "$grade" in
A|a)
echo "🎓 成绩优秀!"
;;
B|b)
echo "📘 成绩良好"
;;
C|c)
echo "📝 成绩及格"
;;
*)
echo "❌ 未知等级"
;;
esac
四、结合命令行参数解析 📥
这是 case 最常见的用途之一,用于解析脚本启动时传入的参数。
✅ 示例:创建一个带参数的备份脚本
#!/bin/bash
case "$1" in
full)
echo "📦 正在执行全量备份..."
tar -czf /backup/full_$(date +%Y%m%d).tar.gz /home /etc
;;
daily)
echo "📅 正在执行每日增量备份..."
rsync -av /home /backup/daily/
;;
help|--help|-h)
echo "可用参数:full | daily | help"
exit 0
;;
*)
echo "❌ 参数错误!请使用 full、daily 或 help"
exit 1
;;
esac
使用方法:
./backup.sh full
./backup.sh daily
./backup.sh --help
五、构建交互式菜单系统 🧩
case 非常适合用来实现命令行菜单界面。
✅ 示例:主菜单脚本
while true
do
echo "==== 主菜单 ===="
echo "1. 创建用户"
echo "2. 查看服务状态"
echo "3. 退出"
read -p "请选择操作(1-3):" choice
case "$choice" in
1)
read -p "请输入用户名:" new_user
useradd "$new_user" && echo "✅ 用户 $new_user 已创建"
;;
2)
systemctl status nginx
;;
3)
echo "👋 正在退出..."
break
;;
*)
echo "❌ 无效选择,请重试"
;;
esac
done
六、实战案例分析 🧪
🎯 场景一:日志级别过滤器 📊
log_level="INFO"
case "$log_level" in
DEBUG)
echo "[DEBUG] 这是调试信息"
;;
INFO)
echo "[INFO] 这是一般信息"
;;
WARN)
echo "[WARN] 这是警告信息"
;;
ERROR)
echo "[ERROR] 这是错误信息"
;;
*)
echo "❌ 未知日志级别"
;;
esac
🎯 场景二:自动识别文件扩展名并处理 📄
file="/tmp/report.docx"
case "$file" in
*.txt)
echo "📄 文本文档"
;;
*.doc|*.docx)
echo "📘 Word 文档"
;;
*.xls|*.xlsx)
echo "📊 Excel 表格"
;;
*.pdf)
echo "📑 PDF 文件"
;;
*)
echo "📂 未知类型"
;;
esac
🎯 场景三:检测系统发行版并执行适配命令 🐧
distro=$(grep ID= /etc/os-release | grep -v VERSION_ID | cut -d= -f2)
case "$distro" in
ubuntu|debian)
echo "APT 包管理器"
sudo apt update
;;
centos|rhel)
echo "YUM 包管理器"
sudo yum makecache
;;
fedora)
echo "DNF 包管理器"
sudo dnf makecache
;;
arch)
echo "Pacman 包管理器"
sudo pacman -Sy
;;
*)
echo "❌ 无法识别系统发行版"
;;
esac
七、不同系统的差异与注意事项 ⚠️
| 项目 | Bash | Dash (Ubuntu 默认) | zsh |
|---|---|---|---|
支持 case |
✅ | ✅ | ✅ |
| 支持通配符 | ✅ | ✅ | ✅ |
| 支持正则表达式 | ❌(需用 [[ ]]) | ❌ | ❌ |
| 推荐脚本开头 | #!/bin/bash |
#!/bin/sh |
#!/bin/zsh |
| 注意缩进与空格 | 是 | 是 | 是 |
📝 小贴士:
- 在 Ubuntu 中默认
/bin/sh是dash,虽然支持case,但不推荐使用高级特性。 - 使用双引号包裹变量,防止路径含空格出错。
- 每个
case分支必须以;;结尾。 - 可以使用
break、continue控制流程。
⚠️ 常见陷阱 & 解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 语法错误 | 缺少 ;; 或 esac |
添加正确的结束符号 |
| 匹配失败 | 模式未覆盖所有可能 | 添加 *) 默认分支 |
| 变量未加引号 | 导致空格或特殊字符解析错误 | 使用双引号包裹变量 |
| 不区分大小写 | 忽略大小写匹配 | 使用 ` |
| 性能问题 | 高频率调用外部命令 | 合理优化逻辑或合并处理 |
🧠 总结与小贴士
| 技巧 | 说明 |
|---|---|
case 是 Shell 的“智能选择器” |
让脚本能快速响应多个固定值 |
| 适合处理命令行参数、菜单选项、状态码等 | 提升代码可维护性 |
推荐配合 read 和 while 使用 |
构建交互式脚本 |
使用 *) 处理默认情况 |
增强容错能力 |
注意 ;; 不能遗漏 |
否则会继续执行下一个分支 |
| 避免嵌套过深 | 保持代码清晰易读 |
📚 推荐练习题(可选)
- 编写一个脚本,接收用户输入的月份名称,输出对应的季节(春、夏、秋、冬)。
- 写一个脚本,根据不同的文件后缀名执行不同的压缩工具(如 .zip/.tar.gz/.7z)。
- 实现一个脚本,模拟计算器功能,接收两个数和运算符(+ - * /),输出结果。
- 编写一个脚本,解析命令行参数并根据参数执行不同的操作(start/stop/restart/status)。
- 创建一个系统诊断脚本,根据不同的平台执行相应的诊断命令(df/free/top)。
🎯 下一章预告:《Shell 函数 Function》
你已经掌握了如何让脚本“多路分支选择”,下一步我们将学习如何将常用代码块封装成函数,提高复用性和可维护性 —— Shell 函数,让你的脚本更模块化、更专业!
需要我继续为你生成下一章内容吗?😊

浙公网安备 33010602011771号