如何在Bash中使用getopts解析含冒号的必填参数
Bash中用getopt/getopts解析带冒号的host:port格式参数的解决方法
问题根因
- 内置
getopts的解析逻辑是遇到第一个不以-开头的参数就会自动停止解析,你把database:3306放在参数最前面,getopts还没处理后面的-t/-i选项就直接终止了 - 你定义的选项串
qt:i:没有以:开头,这种情况下遇到缺失参数的选项时getopts会直接输出错误,不会返回:触发你写的对应分支 - 你在分支中手动调用
shift会打乱getopts内置的OPTIND计数,反而会导致解析逻辑混乱
解决方案
方案一:用内置getopts(兼容性最好,推荐)
调整调用约定,把所有选项放在位置参数host:port前面,调用方式改为:
wait-for -t 60 -i 10 database:3306
对应的代码修改如下:
# 初始化默认值 QUIET=0 TIMEOUT=15 INTERVAL=1 while getopts "qt:i:h" arg; do case "$arg" in q) QUIET=1 ;; t) TIMEOUT="$OPTARG" ;; i) INTERVAL="$OPTARG" ;; h) usage 0 ;; \?) echoerr "未知选项: -$OPTARG" usage 1 ;; :) echoerr "选项 -$OPTARG 缺少必填参数" usage 1 ;; esac done # 移除已经处理完成的选项参数 shift $((OPTIND - 1)) # 剩余第一个参数即为host:port格式的目标地址 HOST_PORT="$1" if [ -z "$HOST_PORT" ]; then echoerr "缺少必填的host:port参数" usage 1 fi # 切分获取主机和端口 HOST=$(cut -d : -f 1 <<< "$HOST_PORT") PORT=$(cut -d : -f 2 <<< "$HOST_PORT")
这个方案兼容所有带Bash的系统,不需要依赖额外工具。
方案二:用GNU getopt支持乱序参数
如果你必须保留host:port放在最前面的调用方式,可以使用GNU版本的getopt工具(注意和内置getopts拼写不同,少一个s),它支持解析位置任意的选项和参数:
# 解析所有参数,支持乱序 OPTIONS=$(getopt -o qt:i:h -- "$@") if [ $? -ne 0 ]; then usage 1 fi eval set -- "$OPTIONS" while true; do case "$1" in -q) QUIET=1 shift ;; -t) TIMEOUT="$2" shift 2 ;; -i) INTERVAL="$2" shift 2 ;; -h) usage 0 ;; --) shift break ;; *) echoerr "未知参数: $1" usage 1 ;; esac done # 剩余第一个参数即为host:port HOST_PORT="$1" HOST=$(cut -d : -f 1 <<< "$HOST_PORT") PORT=$(cut -d : -f 2 <<< "$HOST_PORT")
注意:非Linux环境(如macOS)默认预装的是BSD版本getopt,功能和GNU版本不兼容,如果需要跨平台使用不推荐该方案
内容的提问来源于stack exchange,提问作者Mateusz
相关产品推荐
相关产品推荐

