shell菜单驱动程序应以while true包裹case实现稳定闭环,输入需正则校验与容错,功能模块封装为函数并加确认提示,支持子菜单层级切换与信号捕获清理。

Shell 中的流程控制不只是写几个 if 或 for 就完事,真正体现功力的地方,是把它们组织成一个稳定、可交互、易维护的菜单驱动程序。这类脚本常用于系统巡检、日志清理、服务管理等运维场景,核心在于“用户输入 → 条件分发 → 功能执行 → 返回主菜单”的闭环逻辑。
用 case + while 实现健壮主菜单
菜单驱动程序的骨架必须能持续运行、响应输入、防误操作。推荐用 while true 包裹 case,而不是嵌套多层 if:
- case 天然适合处理离散选项(如 1/2/3/q),比 if-elif 链更清晰、执行更快
- while true 提供无限循环入口,配合 break 可精准退出,避免状态混乱
- 每个菜单项末尾加 echo "" && read -n 1 -p "按任意键继续..." _,防止输出刷屏后看不到结果
输入校验与容错设计
真实环境中用户可能输错、输空、输字母,不能让脚本直接崩溃或误执行:
- 用 read -r choice 读取输入,-r 防止反斜杠被转义
- 用 [[ $choice =~ ^[1-4qQ]$ ]] || { echo "无效选项"; continue; } 做正则校验
- 对数字类选项(如选择第几项日志)额外用 (( choice >= 1 && choice 检查范围
- 所有外部命令调用前加 command -v xxx &>/dev/null || { echo "缺少命令 xxx"; exit 1; }
功能模块封装为函数再调用
每个菜单项对应一个独立函数,而非把大段代码塞进 case 分支里:
- 函数名见名知意,比如 show_disk_usage、rotate_nginx_logs
- 函数内优先使用局部变量:local used_pct=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
- 关键操作前加确认提示:read -p "确定重启 nginx?(y/N) " -n 1 -r; [[ $REPLY =~ ^[yY]$ ]] || continue
- 函数结尾统一返回状态码:return 0 表示成功,非 0 表示异常,便于上层判断
支持子菜单与上下文切换
复杂系统需要二级菜单(如“网络管理 → 查看连接 → 查看监听端口”),这时避免深度嵌套:
- 用变量记录当前层级,例如 menu_level="main" 或 menu_level="network"
- 主循环中根据 menu_level 分发到不同 case 块,每块专注一类功能
- 返回上级菜单用 menu_level="main"; continue,不靠 break 多层循环
- 必要时用 trap 'cleanup; exit' INT TERM 捕获 Ctrl+C,执行清理动作再退出











