36·Shell 基础入门

case 多分支选择

caseswitch

第 36 课 - case 多分支选择

课程:Linux 系统管理与运维 模块:Shell 基础 难度:beginner 标签:case, switch 上一课:if 条件判断 下一课:for 与 while 循环


1. 学习目标

通过本课学习,你将能够:

  • 理解 case 语句的基本语法和工作原理
  • 使用 case 语句根据变量的不同值执行不同的命令块
  • 掌握 case 语句中通配符(如 *?[...])的使用
  • 对比 caseif-elif-else 在多分支选择中的优劣
  • 在 Shell 脚本中应用 case 语句处理实际运维任务

2. 核心概念

什么是 case 语句?

case 语句是 Shell 中用于多分支选择的控制结构,类似于其他编程语言中的 switch 语句。它能够根据一个变量的值,匹配多个可能的模式,并执行对应的命令。

想象一下:你面前有三条路,根据你的目的地(变量值)选择其中一条(执行对应的命令块)。这就是 case 语句的核心思想。

基本语法结构

case $变量 in
    模式1)
        命令块1
        ;;  # 双分号表示分支结束
    模式2)
        命令块2
        ;;
    模式3)
        命令块3
        ;;
    *)  # 默认分支(类似于 else)
        默认命令块
        ;;
esac  # 结束标志

关键要素:

  1. 变量:被检查的值(通常是 $变量
  2. 模式:用 ) 结尾,可以使用通配符
  3. 命令块:匹配成功时执行的命令
  4. 双分号 ;;:标记每个分支的结束
  5. *):默认分支,匹配所有未明确列出的模式
  6. esaccase 的反写,标记整个结构的结束

3. 代码示例

示例 1:基本 case 语句

#!/bin/bash

# 询问用户想查看什么系统信息
echo "请选择要查看的系统信息:"
echo "1) 主机名"
echo "2) IP 地址"
echo "3) 系统版本"
echo "4) 磁盘使用情况"
read -p "请输入选项 (1-4): " choice

case $choice in
    1)
        echo "主机名: $(hostname)"
        ;;
    2)
        echo "IP 地址: $(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}')"
        ;;
    3)
        echo "系统版本: $(cat /etc/os-release | head -n 1)"
        ;;
    4)
        echo "磁盘使用情况:"
        df -h
        ;;
    *)
        echo "错误: 无效选项,请输入 1-4"
        ;;
esac

示例 2:使用通配符匹配

#!/bin/bash

# 根据文件扩展名判断文件类型
file_name="report.txt"

case $file_name in
    *.txt|*.log)  # 匹配 .txt 或 .log 文件
        echo "文本文件: $file_name"
        ;;
    *.jpg|*.png|*.gif)  # 匹配图片文件
        echo "图片文件: $file_name"
        ;;
    *.sh)  # 匹配 Shell 脚本
        echo "Shell 脚本: $file_name"
        ;;
    *.tar|*.gz|*.zip)  # 匹配压缩文件
        echo "压缩文件: $file_name"
        ;;
    *)  # 默认情况
        echo "未知文件类型: $file_name"
        ;;
esac

示例 3:实际运维应用 - 服务管理脚本

#!/bin/bash

service_name="nginx"

case $1 in  # $1 是脚本的第一个参数
    start)
        echo "启动 $service_name 服务..."
        sudo systemctl start $service_name
        ;;
    stop)
        echo "停止 $service_name 服务..."
        sudo systemctl stop $service_name
        ;;
    restart)
        echo "重启 $service_name 服务..."
        sudo systemctl restart $service_name
        ;;
    status)
        echo "查看 $service_name 服务状态:"
        sudo systemctl status $service_name
        ;;
    reload)
        echo "重新加载 $service_name 配置..."
        sudo systemctl reload $service_name
        ;;
    *)
        echo "用法: $0 {start|stop|restart|status|reload}"
        exit 1
        ;;
esac

4. 实践练习

练习 1:基础 case 语句

要求:编写一个脚本,根据用户输入的星期几(1-7),输出对应的英文名称和活动安排(1-Monday 学习, 2-Tuesday 运动...)。

预期输出示例

请输入星期几 (1-7): 3
星期三:Wednesday - 开会日

练习 2:通配符匹配

要求:编写一个脚本,接受一个文件名作为参数,根据文件扩展名输出对应的 MIME 类型(如 .jpgimage/jpeg, .pdfapplication/pdf)。

预期输出示例

./script.sh document.pdf
PDF 文件: application/pdf

练习 3:实际应用 - 自动备份脚本

要求:编写一个备份管理脚本,支持以下操作:

  • daily:执行每日备份
  • weekly:执行每周备份
  • monthly:执行每月备份
  • clean:清理 30 天前的备份
  • list:列出所有备份文件

预期功能

./backup.sh daily
执行每日备份...
备份文件: backup_2023-10-15_daily.tar.gz

5. 常见错误

错误 1:忘记双分号 ;;

# 错误写法
case $var in
    pattern)
        commands
    # 缺少 ;;
next_pattern)
    commands
    ;;
esac

错误 2:模式匹配不精确

# 问题:会匹配以 "start" 开头的任何内容
case $action in
    start)  # 这也会匹配 "starting"、"start service" 等
        echo "Starting..."
        ;;
esac

# 解决方案:使用精确匹配
case $action in
    start)  # 仅匹配 "start"
        echo "Starting..."
        ;;
esac

错误 3:模式中使用了错误的通配符

# 错误:模式中使用了变量,但没加引号
pattern="*.txt"
case $file in
    $pattern)  # 可能不会按预期工作
        echo "Text file"
        ;;
esac

# 正确:直接使用通配符模式
case $file in
    *.txt)
        echo "Text file"
        ;;
esac

错误 4:忘记 esac 结束

# 错误:缺少 esac
case $var in
    pattern)
        commands
        ;;
# 缺少 esac

echo "This will cause syntax error"

错误 5:模式中使用了不支持的正则表达式

# 错误:case 不支持标准正则表达式
case $string in
    [0-9]+\.[0-9]+)  # 这不是标准 case 模式语法
        echo "Decimal number"
        ;;
esac

# 正确:使用支持的通配符
case $string in
    [0-9].[0-9])  # 只匹配单个数字
        echo "Single digit decimal"
        ;;
esac

6. 小结

关键要点回顾:

  1. case 语句是 Shell 中处理多分支选择的强大工具,语法清晰,易于阅读。

  2. 基本结构

    • case $variable in 开始
    • esac 结束(case 的反写)
    • 每个模式以 ) 结尾
    • 用双分号 ;; 分隔不同分支
  3. 模式匹配

    • 支持通配符:*(任意字符)、?(单个字符)、[...](字符类)
    • 可以用 | 分隔多个模式(如 pattern1|pattern2
    • *) 作为默认分支,匹配所有未匹配的模式
  4. 最佳实践

    • 对于简单的值比较,case 通常比 if-elif-else 更简洁
    • 对于复杂的条件判断(如范围判断、数值比较),if-elif-else 更灵活
    • 总是包含默认分支 *) 以处理意外输入
  5. 实际应用

    • 菜单驱动脚本
    • 根据文件类型进行不同处理
    • 服务管理脚本(start/stop/restart)
    • 命令参数解析

下一步学习建议:

  • 尝试将之前的 if-elif-else 脚本改写为 case 版本
  • 结合 case 和函数创建更模块化的脚本
  • 学习在 case 中使用正则表达式的技巧(通过其他命令实现)

预告:下一课我们将学习 Shell 中的循环结构,包括 for 循环和 while 循环,这是自动化批量处理任务的关键技术。

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「for 与 while 循环」 以巩固所学知识。