基于 Bash 脚本项目实战:构建一个交互式多选项菜单(系统状态检查器)
2026/9/17 6:43:22 网站建设 项目流程

基于 Bash 脚本项目实战:构建一个交互式多选项菜单(系统状态检查器)

【免费下载链接】introduction-to-bash-scriptingFree Introduction to Bash Scripting eBook项目地址: https://gitcode.com/GitHub_Trending/in/introduction-to-bash-scripting

本文内容严格依据仓库中 ebook/es/content/016-creating-an-interactive-menu-in-bash.md 的教程主体,并结合仓库内英文原版章节、前序章节脚本及 scripts/shellcheck-ebook.sh 质量校验脚本进行补充与验证而成。


导读

在完成首个服务器状态检查脚本(第 15 章)之后,下一步自然是让脚本具备"人机交互"能力:用户输入一个数字,脚本执行对应动作,然后循环等待下一次选择,直到用户主动退出。这正是本文的核心主题——用 Bash 的case分支语句 +read读取输入,构建一个带彩色提示的交互式多选项菜单

本篇指南将带领你完成:

  • 规划菜单需要暴露的功能(内存、CPU、TCP 连接数、内核版本四项系统检查);
  • 复用并改造上一章的检查函数;
  • 使用 ANSI 转义码为菜单添加绿/蓝/红色高亮;
  • case ... esac结构编写菜单循环与默认错误分支;
  • 完整运行测试并了解仓库自带的 shellcheck 代码质量校验工具。

读完本文,你将掌握 Bash 交互式菜单的标准范式,并能把它套用到自己的运维、部署或工具类脚本中。


一、功能规划:让服务器状态检查脚本"可选"

回顾上一章(第 15 章:编写你的第一个 Bash 脚本),我们构建了一个一次性输出全部信息的status.sh。本文要在它基础上加入菜单,让用户选择要执行哪一项检查:

  • 检查当前磁盘/内存使用情况;
  • 检查当前 CPU 负载;
  • 检查当前内存(RAM)使用情况;
  • 检查内核精确版本。

如果你手头没有上一章的脚本,这里就是完整的基准脚本(对应英文原版 ebook/en/content/015-writing-your-first-bash-script.md 第 122-174 行的最终版本,也是 第 17 章远程执行 直接复用的同款脚本):

#!/bin/bash ## # BASH 菜单脚本,用于检查: # - 内存使用 # - CPU 负载 # - TCP 连接数 # - 内核版本 ## server_name=$(hostname) function memory_check() { echo "" echo "Memory usage on ${server_name} is: " free -h echo "" } function cpu_check() { echo "" echo "CPU load on ${server_name} is: " echo "" uptime echo "" } function tcp_check() { echo "" echo "TCP connections on ${server_name}: " echo "" wc -l < /proc/net/tcp echo "" } function kernel_check() { echo "" echo "Kernel version on ${server_name} is: " echo "" uname -r echo "" } function all_checks() { memory_check cpu_check tcp_check kernel_check }

几个值得注意的细节:

  • server_name=$(hostname)$()是命令替换,Bash 会先执行括号内的hostname命令,再把输出赋给变量,之后所有函数都能引用${server_name}
  • 函数定义遵循 第 12 章《Bash 函数》 的规范function 函数名() { ... },调用时直接写函数名、不带括号;
  • tcp_checkwc -l < /proc/net/tcp统计连接行数/proc/net/tcp是 Linux 内核导出的 TCP 连接表,每一行代表一条连接,行数减去表头即连接数。西班牙语版此处写作cat /proc/net/tcp | wc -l,效果等价,但wc -l < 文件免去了管道和多余进程,是更简洁的写法;
  • all_checks作为聚合函数,依次调用四个子函数,对应菜单里的 "Check All / 全部检查" 选项。

注意:free -huptimeuname -r均为 Linux 自带命令,因此本脚本面向 Linux 环境;macOS 上部分输出格式会略有差异。


二、为菜单添加颜色:ANSI 转义码与颜色函数

纯文本菜单能看,但不够直观。为了让用户"一眼"看清选项编号与提示语,我们引入 ANSI 颜色转义码。Bash 脚本中颜色通常以\e[xxm(等价于\033[xxm)形式出现,\e即 ESC 转义字符。

在脚本开头添加如下颜色变量与颜色函数(英文原版见 ebook/en/content/016-creating-an-interactive-menu-in-bash.md 第 80-99 行,西班牙语版为verde/azul/clear三色,英文版额外定义了red红色):

## # 颜色变量 ## green='\e[32m' blue='\e[34m' red='\e[31m' clear='\e[0m' ## # 颜色函数 ## ColorGreen(){ echo -ne "${green}${1}${clear}" } ColorBlue(){ echo -ne "${blue}${1}${clear}" }

2.1 逐个解释

元素含义
\e[32m绿色前景色转义序列
\e[34m蓝色前景色转义序列
\e[31m红色前景色转义序列(用于错误提示)
\e[0m重置所有颜色与样式,防止颜色"泄漏"到后续输出
  • ColorGreen(){ ... }ColorBlue(){ ... }接收第一个参数$1(即要上色的文本),输出格式为颜色码 + 文本 + 重置码
  • echo -ne中的-n表示不追加换行,-e表示解析转义序列(\e\n等)。这是\e[32m能生效的关键,普通echo会把它当字面文本输出。

2.2 颜色函数的使用方式

echo -ne "$(ColorBlue 'Some text here')"

上面这条命令会把Some text here以蓝色打印到终端。其原理是命令替换$(...)先把ColorBlue 'Some text here'的输出(即\e[34mSome text here\e[0m)取回,再交给echo -ne输出。这个模式在菜单函数中会被反复使用,为每个选项编号染色。


三、添加菜单函数:case ... esac分支核心

有了检查函数和颜色函数,最后一步是编写menu()函数:先打印菜单,再读取用户输入,最后用case语句根据输入分派到对应函数。

menu(){ echo -ne " My First Menu $(ColorGreen '1)') Memory usage $(ColorGreen '2)') CPU load $(ColorGreen '3)') Number of TCP connections $(ColorGreen '4)') Kernel version $(ColorGreen '5)') Check All $(ColorGreen '0)') Exit $(ColorBlue 'Choose an option:') " read a case $a in 1) memory_check ; menu ;; 2) cpu_check ; menu ;; 3) tcp_check ; menu ;; 4) kernel_check ; menu ;; 5) all_checks ; menu ;; 0) exit 0 ;; *) echo -e "${red}Wrong option.${clear}"; menu ;; esac }

3.1 逐段拆解

第一步:打印带颜色的菜单选项

echo -ne " My First Menu $(ColorGreen '1)') Memory usage ... $(ColorBlue 'Choose an option:') "
  • 外层字符串使用双引号包裹,因此内部的$(ColorGreen '1)')命令替换会被执行,把选项编号染成绿色;
  • 选项文本保留为白色,形成"绿色编号 + 白色说明 + 蓝色提示"的层次;
  • -n保证打印完提示后光标停留在同一行,方便用户直接输入。

第二步:读取用户输入

read a

read是 Bash 内置命令,读取一行标准输入并存入变量aread的用法详见 第 5 章《Bash 用户输入》)。此处未加-p提示参数,因为提示语已经由上一行echo打印。

第三步:case分支分派

case $a in 1) memory_check ; menu ;; 2) cpu_check ; menu ;; ... 0) exit 0 ;; *) echo -e "${red}Wrong option.${clear}"; menu ;; esac

这正是 第 10 章《Bash 条件语句》 中case语法(case $变量 in 模式) 命令 ;; ... esac)的实战应用。逐条解读:

  • 每个数字模式匹配后,先执行对应检查函数,再递归调用menu——这是让菜单"回到开头、循环显示"的关键设计(memory_check ; menu中的分号是顺序执行分隔符,先检查、后回菜单);
  • 0) exit 0 ;;:选择 0 时调用exit 0干净退出脚本;
  • *)默认通配分支:任何不匹配 0-5 的输入都会落入此处,用红色打印Wrong option.后重新调用menu,让用户重新选择。这等价于if-else链中的else,是防止非法输入导致脚本崩溃的保险丝。

关于原文的一处笔误:西班牙语版在默认分支里写了WrongCommand(一个未定义函数),英文原版为menu。本文采用修正后的写法——在出错后重新调用menu返回菜单,这才是该分支的预期行为。

第四步:调用菜单

函数定义之后必须显式调用才会执行:

# 调用菜单函数 menu

menu是脚本最后一行,脚本一启动就进入菜单循环。


四、完整脚本:可直接运行的menu.sh

将以上内容组合,得到完整的交互式菜单脚本(与英文原版 ebook/en/content/016-creating-an-interactive-menu-in-bash.md 第 184-278 行的完整版一致):

#!/bin/bash ## # BASH 菜单脚本,用于检查: # - 内存使用 # - CPU 负载 # - TCP 连接数 # - 内核版本 ## server_name=$(hostname) function memory_check() { echo "" echo "Memory usage on ${server_name} is: " free -h echo "" } function cpu_check() { echo "" echo "CPU load on ${server_name} is: " echo "" uptime echo "" } function tcp_check() { echo "" echo "TCP connections on ${server_name}: " echo "" wc -l < /proc/net/tcp echo "" } function kernel_check() { echo "" echo "Kernel version on ${server_name} is: " echo "" uname -r echo "" } function all_checks() { memory_check cpu_check tcp_check kernel_check } ## # 颜色变量 ## green='\e[32m' blue='\e[34m' red='\e[31m' clear='\e[0m' ## # 颜色函数 ## ColorGreen(){ echo -ne "${green}${1}${clear}" } ColorBlue(){ echo -ne "${blue}${1}${clear}" } menu(){ echo -ne " My First Menu $(ColorGreen '1)') Memory usage $(ColorGreen '2)') CPU load $(ColorGreen '3)') Number of TCP connections $(ColorGreen '4)') Kernel version $(ColorGreen '5)') Check All $(ColorGreen '0)') Exit $(ColorBlue 'Choose an option:') " read a case $a in 1) memory_check ; menu ;; 2) cpu_check ; menu ;; 3) tcp_check ; menu ;; 4) kernel_check ; menu ;; 5) all_checks ; menu ;; 0) exit 0 ;; *) echo -e "${red}Wrong option.${clear}"; menu ;; esac } # 调用菜单函数 menu

4.1 运行与预期输出

创建一个以.sh结尾的文件(例如menu.sh),将上述内容粘贴保存,然后运行:

bash menu.sh

预期输出如下(颜色无法在文本中体现,实际终端中编号为绿色、提示语为蓝色):

My First Menu 1) Memory usage 2) CPU load 3) Number of TCP connections 4) Kernel version 5) Check All 0) Exit Choose an option:

此时终端等待你输入。选择不同数字会触发不同的函数:

  • 输入1→ 执行memory_check,输出free -h的内存统计;
  • 输入2→ 执行cpu_check,输出uptime的负载信息;
  • 输入3→ 执行tcp_check,输出/proc/net/tcp的行数;
  • 输入4→ 执行kernel_check,输出uname -r的内核版本;
  • 输入5→ 执行all_checks,依次跑完上面四项;
  • 输入0exit 0退出脚本;
  • 输入其他任意内容 → 红色提示Wrong option.,并重新显示菜单。

每次检查完成后菜单都会再次出现,形成"选择 → 执行 → 返回菜单"的循环,直到你输入0

4.2 给脚本加执行权限(可选)

虽然bash menu.sh无需可执行权限即可运行,但若想直接以./menu.sh方式运行,需要两步:

chmod +x menu.sh ./menu.sh

其中首行#!/bin/bash(shebang,详见 第 1 章《Bash 入门》 与 第 3 章《Hello World》)会告诉系统用/bin/bash解释器执行本脚本。


五、仓库自带的代码质量校验:shellcheck 如何守护这类脚本

这个开源电子书仓库不仅提供教程文字,还自带一个质量保障脚本 scripts/shellcheck-ebook.sh。它会自动提取英文版 ebook/en/content 目录下所有 Markdown 文件中的```bash代码块,逐个交给 shellcheck 静态检查,确保书中的每个脚本片段都可运行、无低级错误。

./scripts/shellcheck-ebook.sh [ebook_dir] # ebook_dir 默认为 ebook/en/content

几个与本文菜单脚本直接相关的实现细节(scripts/shellcheck-ebook.sh 第 90-96 行):

  • 若代码块第一行匹配^[0-9]+\)(例如菜单的示例输出1) Memory usage),会被识别为"select-menu 输出/菜单渲染结果",判定为不可直接执行的展示文本而跳过检查;
  • 若某个代码块所在标题行含 "Incorrect"、"### Error"、"Output" 等字样,也会被跳过——说明仓库刻意收录了一些"错误示范"用于教学对比;
  • 未跳过的真实脚本代码块则使用shellcheck -S warning -e "SC2034,SC2154,..."严格校验,排除项如SC2034(变量看似未使用)正是考虑到"教程片段中定义的变量会在后续片段使用"的教学场景。

这套机制从侧面印证了本文菜单脚本的写法(case分支、颜色函数、exit 0退出)是符合 shellcheck 警告级别要求的规范代码。你写完自己的menu.sh后,也可以用同样的方式自检:

shellcheck menu.sh

六、延伸:这个菜单还能怎么用

掌握交互式菜单范式后,你可以把它迁移到仓库后续章节的真实场景中:

  • 第 17 章《在多台远程服务器上执行 Bash 脚本》 直接复用了本章的检查函数集(memory_checkcpu_checktcp_checkkernel_check),只是将菜单层替换为 SSH 批量循环——这说明"功能函数"与"交互界面"分离的设计让脚本极易复用;
  • case的匹配值扩展为更友好的语义字符串(如quitall),或通过read -p携带提示、用select内置命令生成编号菜单,都是自然的升级方向;
  • 颜色函数可以扩充更多色号(\e[33m黄、\e[36m青等)和样式(\e[1m加粗),用于区分不同级别的输出。

结语

至此,你已掌握 Bash 交互式菜单的完整构建方法:先用函数封装业务逻辑,再用 ANSI 转义码优化视觉呈现,最后用case分支 +menu递归调用实现"选择-执行-循环-退出"的交互闭环。这个模式可以内嵌到任何需要用户做出多选一的脚本中——从系统监控工具到部署向导都适用。

建议在本地终端中亲手运行一遍menu.sh,故意输入几个非法字符观察默认分支的容错行为,然后按自己的需求增删菜单项。当你需要确认脚本写法符合规范时,仓库的 scripts/shellcheck-ebook.sh 就是现成的参考答案。

继续阅读下一章(第 17 章:远程批量执行),看看这套检查函数如何被改造成"一条命令跑遍所有服务器"的运维利器。

【免费下载链接】introduction-to-bash-scriptingFree Introduction to Bash Scripting eBook项目地址: https://gitcode.com/GitHub_Trending/in/introduction-to-bash-scripting

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询