Bash脚本case语句default(*)分支为何总是被执行?
Bash参数解析脚本异常触发退出问题排查
问题复现
编写了读取脚本入参并传递给解析函数的Bash脚本,完整代码如下:
#!/usr/bin/env bash function main() { parseargs2 "$@" } function parseargs2() { MAINCOMMAND=$1 shift while [ $# -gt 0 ]; do case $1 in -s|--service) SERVICE_NAME="$2" ;; -r|--registry) REGISTRY="$2" ;; -h|--help) HELP=true ;; *) echo "help" && exit 1;; esac shift done echo "SERVICE_NAME: $SERVICE_NAME" echo "REGISTRY: $REGISTRY" echo "HELP: $HELP" echo "cmd: $MAINCOMMAND" } main "$@"
使用如下命令运行脚本时,总会触发打印help提示后退出的逻辑,但移除case语句中的*)通配匹配分支后,脚本可以正常运行:
./example.sh build --service api --registry dockerhub
故障根因
问题由参数移位逻辑错误导致:
循环内每次case匹配完成后仅执行1次shift,仅会移除当前位置的1个参数。对于-s/--service、-r/--registry这类需要携带参数值的选项,单次shift只会把选项名本身移出参数列表,选项对应的取值(比如示例中的api、dockerhub)会留在参数队列中,下一轮循环时这个取值会被*)通配分支捕获,直接触发打印help、退出脚本的逻辑。
以运行命令为例拆解执行流程:
- 进入
parseargs2函数后,首先取第一个参数build赋值给MAINCOMMAND,执行1次shift后剩余参数为--service api --registry dockerhub - 第一轮while循环匹配到
--service分支,将SERVICE_NAME赋值为api,随后执行循环末尾的shift,此时剩余参数为api --registry dockerhub - 第二轮while循环取到的$1为
api,无法匹配任何预定义的选项规则,直接进入*)分支执行退出逻辑。
修复方法
针对需要携带参数值的选项分支,在分支内执行shift 2,一次性将选项名和对应的参数值都移出参数列表即可;不需要携带值的开关类选项(比如-h/--help)保留原有移位逻辑即可。
修复后的参数解析函数代码如下:
function parseargs2() { MAINCOMMAND=$1 shift while [ $# -gt 0 ]; do case $1 in -s|--service) SERVICE_NAME="$2" shift 2 ;; -r|--registry) REGISTRY="$2" shift 2 ;; -h|--help) HELP=true shift ;; *) echo "help" && exit 1;; esac done echo "SERVICE_NAME: $SERVICE_NAME" echo "REGISTRY: $REGISTRY" echo "HELP: $HELP" echo "cmd: $MAINCOMMAND" }
内容的提问来源于stack exchange,提问作者viktor
相关产品推荐
相关产品推荐

