Shell脚本精读 · S08-04 | 命令行与交互输入:`getopts` 与 `select` 菜单

📅 2026/7/17 19:56:06
Shell脚本精读 · S08-04 | 命令行与交互输入:`getopts` 与 `select` 菜单
模块S08 函数与脚本结构篇号S08-04 / 42预计阅读50 分钟主线Bash文章目录本篇目标30 秒速览正文1. 为何需要 getopts2. getopts 基本结构3. optstring 规则4. OPTARG 与 OPTIND5. 错误分支\? 与 :6. 完整入口模板7. getopts 的局限与长选项7.1 先用 case 处理 --再 getopts7.2 只用短选项8. 与 case shift 对照9. select交互菜单10. select 读法要点11. select PS3 无限菜单12. 读脚本检查清单练习判断题实操题 1getopts实操题 2select改错题读脚本题S08 模块小结下一篇预告本篇目标掌握getopts解析短选项-h-o file以及 Bashselect做交互菜单。能写出带usage、OPTARG/OPTIND的入口脚本并在读代码时区分getopts与caseshift两种风格。本篇为S08 模块收尾。30 秒速览getoptsPOSIX 内置适合单字符选项-h-v-o带参选项在 optstring 里写o:。循环后执行shift $((OPTIND - 1))剩下$为位置参数。OPTARG当前选项的参数OPTIND下一个待处理参数下标。--、--long长选项getopts不直接支持常另用case预扫或只用短选项。select从列表生成编号菜单用户输入序号PS3改提示符。非交互脚本用getopts运维小工具、本地菜单可用select。正文1. 为何需要getoptsS03-03、S06-02 用whilecaseshift解析选项短脚本足够。选项一多getopts更规整自动处理-abc粘在一起等价-a -b -c统一OPTARG取参数错误时退出码、?分支一致# 手写要处理 -vh、-hv、-v -h 等多种写法# getopts 一轮循环即可2.getopts基本结构verbose0outfilewhilegetopts:hvo:opt;docase$optinh)usageexit0;;v)verbose1;;o)outfile$OPTARG;;\?)echoinvalid option: -$OPTARG2usageexit2;;:)echooption -$OPTARGrequires an argument2usageexit2;;esacdoneshift$((OPTIND-1))# 此处 $ 为剩余位置参数部分含义getopts :hvo: opt合法选项为h、v、oo需要参数case $opt分支处理shift $((OPTIND - 1))丢掉已消费的选项保留位置参数3. optstring 规则whilegetoptshf:o:opt;do写法含义h开关无参数o:选项-o必须跟一个参数存入OPTARG前导:静默模式非法选项、缺参时getopts不打印默认错误由你在?、:分支处理推荐在 optstring最前加:上例:hvo:错误信息自己控制。示例./tool.sh-v-oresult.txt input1 input2# 循环结束后 OPTIND 指向 input1shift 后 $ input1 input2粘写./tool.sh-vh-oout.txtfile# 等价 -v -h -o out.txt4.OPTARG与OPTIND变量含义OPTARG当前选项的参数如-o FILE里的 FILE非法选项时可能是非法字符OPTIND下一个要处理的$n下标初始为 1echoremaining:$*echoOPTIND$OPTINDshift $((OPTIND - 1))是固定套路把$1…$(OPTIND-1)选项吃掉$1变成第一个非选项参数。5. 错误分支\?与:case分支触发\?遇到了 optstring 里没有的选项:需要参数的选项后面没跟参数optstring 前导:时whilegetopts:f:opt;docase$optinf)file$OPTARG;;\?)echobad opt: -$OPTARG2;exit2;;:)echo-$OPTARGneeds arg2;exit2;;esacdone6. 完整入口模板#!/usr/bin/env bashset-euopipefailusage(){echousage:$0[-hv] [-o outfile] inputs...2}verbose0outfilewhilegetopts:hvo:opt;docase$optinh)usage;exit0;;v)verbose1;;o)outfile$OPTARG;;\?)usage;exit2;;:)usage;exit2;;esacdoneshift$((OPTIND-1))(($#1))||{usage;exit2;}((verbose))set-x# 使用 outfile 与 $与 S01-04 骨架、S08-01main可合并选项解析在main开头。7.getopts的局限与长选项getopts只处理单字符-x不识别-output为-output。长选项常见做法7.1 先用case处理--再getoptswhile(($#0));docase$1in--help)usage;exit0;;--verbose)verbose1;shift;;--)shift;break;;-*)break;;# 交给 getopts*)break;;esacdonewhilegetopts:ho:opt;do...doneshift$((OPTIND-1))7.2 只用短选项许多内部脚本约定-h-v-o文档写清即可。读脚本见到--foo先看是case手写还是外部getopt/getopt_long命令本专栏以内置getopts为主。8. 与caseshift对照getoptscaseshift短选项组合-vh自动拆分需自己写或多次 shift长选项--help不支持容易写代码量选项多时更短选项少时直观可移植POSIX Bash/shPOSIXS06-03 里while case选项循环与本篇getopts常出现在同一项目的不同脚本中。9.select交互菜单PS3Choose action: selectactioninstart stop status quit;docase$actioninstart)echoaction$action;break;;stop)echoaction$action;break;;status)echoaction$action;;quit)break;;)echoinvalid;;*)echounknown:$REPLY;;esacdone关键点与核心变量基本概述select命令是Bash中用于创建交互式菜单的内置工具。它能把一个选项列表变成带编号的菜单让用户通过输入数字来选择无线循环select本身是无限循环会不断显示菜单并等待输入。要退出循环需在代码块内使用break语句代码块select的代码块中必须要有代码不可以为空否则会执行报错PS3 变量用于自定义菜单的提示符默认是#?。通过修改它可以让提示更清晰REPLY 变量用于记录用户输入的文本action变量自定义循环变量用于记录选项中的单词如果输入的文本不是菜单中的编号那么action变量为空运行效果示意1) start 2) stop 3) status 4) quit Choose action: 2用户输入2→actionstop。10.select读法要点selectfin*.sh;do[[-n$f]]||{echobad choice;continue;}shellcheck$fbreakdone点说明用户输入数字选对应项越界时$f为空用户输入非数字文本可能匹配列表中的词少见用法break退出select循环S07-03非交互无 stdin 时select不合适用参数或配置文件select是 Bash 特性#!/bin/sh脚本里不应出现。11.selectPS3 无限菜单PS3 whiletrue;doselectcmdinbuildtestcleanexit;docase$cmdinbuild|test|clean)$cmd;break;;exit)return02/dev/null||exit0;;*)echo?;;esacdonedone外层while true执行完一次操作后再显示菜单运维小工具常见。12. 读脚本检查清单选项解析后是shift $((OPTIND-1))了吗带参选项在 optstring 里是o:吗--long是getopts还是case处理的usage是否与真实选项一致select是否处理了空选择、break退出练习判断题getopts可以直接解析--outputfile这种长选项。-o需要参数时optstring 应包含o:。getopts循环结束后应shift $((OPTIND-1))再处理位置参数。select中用户选无效编号时循环变量常为空串。PS3用来设置select的提示字符串。参考答案错内置 getopts 只管单字符-x长选项另处理。对。对。对。对。实操题 1getopts为脚本补全选项-h帮助-n count重复次数默认 1剩余参数为要 echo 的字符串。./say.sh -n 3 hello→ 打印三行hello。参考答案#!/usr/bin/env bashset-euopipefailusage(){echousage:$0[-n count] message2;}count1whilegetopts:hn:opt;docase$optinh)usage;exit0;;n)count$OPTARG;;\?)usage;exit2;;:)usage;exit2;;esacdoneshift$((OPTIND-1))(($#1))||{usage;exit2;}msg$1for((i0;icount;i));doecho$msgdone实操题 2select写菜单项为list、show、quit选list打印listing选show打印status选quit退出无效输入提示?并重新显示菜单。参考答案PS3menu selectactinlist show quit;docase$actinlist)echolisting;break;;show)echostatus;break;;quit)break2;;*)echo?;;esacdone单次执行后break若要反复菜单可外包while true。改错题whilegetoptshv:oopt;docase$optino)out$OPTARG;;v)verbose1;;esacdoneshift$OPTINDfile$1参考o应写作o:getopts hv:o:。shift $OPTIND→shift $((OPTIND - 1))。建议 optstring 前导:并处理\?、:。case $opt→case $opt。读脚本题下面片段执行./tool.sh -o a.txt -v b.txt后outfile和第一个位置参数分别是什么whilegetopts:o:vopt;docase$optino)outfile$OPTARG;;v)verbose1;;esacdoneshift$((OPTIND-1))参考答案outfilea.txtverbose1$1为b.txt-v后的b.txt被当作位置参数不是-v的参数。S08 模块小结篇号主题读脚本时S08-01函数main、usage、return/exitS08-02local函数内变量是否污染全局S08-03source库 vs 入口、BASH_SOURCE路径S08-04getopts/select选项怎么解析、有无交互菜单下一模块S09进入进程、管道与重定向。下一篇预告S09-01《重定向基础2与 here-doc》— 标准输出/错误、追加写文件与 here 文档。