一、为什么 case 很适合做菜单类脚本

原笔记把 case 定位得很清楚:它非常适合“固定选项”的判断场景,例如:

  • start|stop|restart|status
  • 菜单编号 1|2|3|4
  • yes|no

相比一长串 if ... elif ... elsecase 在这些场景下更清晰,也更容易维护。

标准格式如下:

case "$choice" in
    start)
        echo start
        ;;
    stop)
        echo stop
        ;;
    restart)
        echo restart
        ;;
    *)
        echo "错误输入"
        ;;
esac

二、实战:菜单选择脚本怎么写

原笔记给了一个“会所菜单”的练习脚本,本质上就是练 case

#!/bin/bash
cat <<EOF
##############olding私人高级会所#####################
输入1,选择138套餐) 吃饱套餐
输入2,选择443套餐) 吃饱喝足套餐
输入3,选择888套餐) 吃喝拉撒套餐
输入4,选择1688套餐) 你想干啥就干啥套餐
输入其他内容,退出
EOF

read -p "尊敬的VIP用户,请输入你的选择:" num

case "$num" in
    1) echo "138套餐) 吃饱套餐" ;;
    2) echo "443套餐) 吃饱喝足套餐" ;;
    3) echo "888套餐) 吃喝拉撒套餐" ;;
    4) echo "1688套餐) 你想干啥就干啥套餐" ;;
    *) echo "选择错误,请充值" ;;
esac

这类脚本虽然偏练习性质,但已经体现了 case 最核心的使用方式。

三、实战:识别 yes/no 这类多写法输入

case 还有一个很好用的地方:一个分支可以匹配多个模式。

#!/bin/bash
read -p "input yes or no: " xuan

case "$xuan" in
    yes|y|Y|Yes) echo "你输入的是yes" ;;
    no|n|N|No) echo "你输入的是no" ;;
    *) echo "无法识别输入" ;;
esac

这比在 if 里不停写 -o 更直观。

四、为什么写脚本时要尽量使用函数

原笔记对函数的总结可以概括成 3 点:

  • 把重复代码抽出来,减少脚本冗余
  • 让脚本更模块化
  • 出现问题时方便调试和定位

常见定义方式有下面几种:

function show_a() {
    echo 1
}

show_b() {
    echo 2
}

function show_c {
    echo 3
}

实际工作里最常见的是第二种:name() { ... }

五、函数基础用法和传参方式

最基础的函数示例如下:

#!/bin/bash
show() {
    echo 1
    echo 2
    echo 3
    echo "上山打老虎"
}

show

函数也支持位置参数,规则和脚本传参类似:

  • 函数里的 $1$2 指的是函数参数
  • 函数里的 $# 是函数参数个数
  • 函数里的 $@$* 是函数收到的全部参数
  • 函数里的 $0 仍然是脚本名,不是函数名

这意味着你完全可以把脚本中的某个步骤做成“可传参函数”。

六、实战:用函数和 case 写服务管理脚本

原笔记最典型的综合案例,是给 sersync 写一个服务管理脚本:

#!/bin/bash
choice=$1

sersync_start() {
    sersync2 -rdo /app/tools/sersync/conf/confxml.xml
}

sersync_stop() {
    sersync_pid=$(ps -ef | grep sersync2 | grep -v grep | awk '{print $2}')
    kill $sersync_pid
}

sersync_restart() {
    sersync_stop
    sersync_start
}

sersync_status() {
    sersync_count=$(ps -ef | grep sersync2 | grep -v grep | wc -l)
    if [ $sersync_count -eq 0 ]; then
        echo "sersync is stopped"
    else
        sersync_pid=$(ps -ef | grep sersync2 | grep -v grep | awk '{print $2}')
        echo "sersync is running ${sersync_pid}"
    fi
}

error_msg() {
    echo "Usage: $0 {start|stop|restart|status}"
}

case "$choice" in
    start) sersync_start ;;
    stop) sersync_stop ;;
    restart) sersync_restart ;;
    status) sersync_status ;;
    *) error_msg ;;
esac

这个脚本已经具备了服务管理脚本最关键的骨架:

  • 参数入口清晰
  • 功能拆分为函数
  • case 负责总调度
  • 错误输入有统一提示

七、把脚本写成“变量区 + 函数区 + 主流程”

综合原笔记内容,最推荐的 Shell 脚本组织方式是:

1、先定义变量。 2、再定义函数。 3、最后写主流程或 case 入口。

也就是类似下面这个结构:

#!/bin/bash

# 1. vars
choice=$1

# 2. functions
start_service() {
    echo start
}

stop_service() {
    echo stop
}

# 3. main
case "$choice" in
    start) start_service ;;
    stop) stop_service ;;
    *) echo "Usage: $0 {start|stop}" ;;
esac

这种结构对后期维护、排障和扩展都最友好。

八、这篇内容真正要学到什么

如果把 case 和函数章节各提炼出一个核心结论,那就是:

  • 固定分支选择,优先用 case
  • 重复逻辑和独立步骤,优先抽成函数

一旦把这两个习惯用到服务管理、巡检和发布脚本里,Shell 自动化脚本的质量就会立刻提升一个层级。