Shell脚本中是否可以将getopts与可选位置参数混合使用?
解决方案
核心逻辑
要实现选项与位置参数顺序无关,原生bash内置的getopts无法满足需求,它遇到非-开头的参数就会停止解析。我们改用GNU版本的getopt工具实现,它原生支持混序参数解析,适配你现有所有选项规则的同时,还能轻松提取可选的额外信息。
完整修改后代码
#!/bin/bash # 初始化变量 test=false help=false verbose=false modeCount=0 msg="restarted" info="" # 用GNU getopt解析参数,支持混序 OPTIONS=":aeghmstv" parsed=$(getopt -o "$OPTIONS" -- "$@") if [ $? -ne 0 ]; then echo "Error: Invalid option; use the h option for help" exit 1 fi eval set -- "$parsed" # 处理解析后的选项 while true; do case "$1" in -a) # 自动重启 ((modeCount+=1)) msg="$msg automatically" shift ;; -e) # 错误触发重启 ((modeCount+=1)) msg="$msg due to an error" shift ;; -g) # Git pull触发重启 ((modeCount+=1)) msg="$msg on git pull" shift ;; -h) # 帮助 help=true shift ;; -m) # 手动重启 ((modeCount+=1)) msg="$msg manually" shift ;; -s) # 启动触发重启 ((modeCount+=1)) msg="$msg on startup" shift ;; -t) # 测试模式 test=true shift ;; -v) # 详细模式 verbose=true shift ;; --) # 选项结束标记,剩余为位置参数 shift break ;; *) # 异常分支 echo "Error: Unknown parameter" exit 1 ;; esac done # 提取可选的额外信息,最多取第一个位置参数,如需支持多参数可改为info="$*" if [ $# -ge 1 ]; then info="$1" fi # 原有输入校验逻辑 if [ "$help" == true ]; then if [ $modeCount -gt 0 ] || [ "$test" == true ] || [ "$verbose" == true ] || [ -n "$info" ]; then echo "Error: No other options or parameters can be used with h; use the h option for help" else # 这里替换为你自己的帮助函数实现即可 echo "Usage: $0 [OPTIONS] [extra_info]" echo "Options:" echo " -a Automatic restart" echo " -e Error-triggered restart" echo " -g Git pull-triggered restart" echo " -h Show help" echo " -m Manual restart" echo " -s Startup-triggered restart" echo " -t Testing mode" echo " -v Verbose mode" fi exit fi if [ $modeCount != 1 ]; then echo "Error: 1 log message option must be used; use the h option for help" exit fi # 拼接额外信息 if [ -n "$info" ]; then msg="$msg: $info" fi # 你原有日志输出逻辑,这里做演示 echo "$(date -Iseconds) $msg"
效果验证
两种调用方式都会输出预期结果:
- 选项在前:
./restart.sh -a "daily restart" # 输出示例:2024-05-20T14:30:00+08:00 restarted automatically: daily restart
- 位置参数在前:
./restart.sh "daily restart" -a # 输出和上面完全一致
不传入额外参数时也能正常运行:
./restart.sh -a # 输出示例:2024-05-20T14:30:00+08:00 restarted automatically
内容的提问来源于stack exchange,提问作者Riggs Markham
相关产品推荐
相关产品推荐

