Bash脚本如何实现支持通配符的命令行选项稳健解析
命令行通配符选项解析方案
首先明确基础逻辑:Bash的通配符展开是在命令执行前完成的,你输入rando -s /angio/repo/A*时,shell会先把/angio/repo/A*展开为所有匹配的文件路径,再传给你的函数,因此实际传入的参数形式为rando -s /angio/repo/A1 /angio/repo/A2 /angio/repo/A3 ...。你原来的代码只取$2必然会遗漏路径,还会把后续匹配到的文件误判为其他选项,导致解析异常。
另外你原有代码存在几个明显错误:
- 自定义IFS拆分
=的写法会破坏带空格的文件名,set -- $*的写法完全没必要 -s赋值写为src=$( "$2" ),这会把第二个参数当做命令执行,属于语法错误,应直接赋值- 未考虑通配符展开后多路径的场景,
-s对应的参数是后续所有非-开头的参数,直到遇到下一个选项为止
修复后的可用实现
rando () { local incl=() fls=() src=() dst=() local narg="$#" while (( narg > 0 )); do local opt="$1" case $opt in "-s"|"--src"|"--source") # 消耗当前选项后,收集后续所有非选项参数作为src路径 shift 1 narg=$((narg - 1)) while (( narg > 0 )) && [[ ! $1 =~ ^- ]]; do src+=("$1") shift 1 narg=$((narg - 1)) done ;; "-d"|"--dst"|"--destin") # 同理处理dst的多路径场景 shift 1 narg=$((narg - 1)) while (( narg > 0 )) && [[ ! $1 =~ ^- ]]; do dst+=("$1") shift 1 narg=$((narg - 1)) done ;; "--") shift 1 narg=$((narg - 1)) break ;; "-"*) printf '%s\n' "Unknown option: $opt" shift 1 narg=$((narg - 1)) ;; *) fls+=("$1") shift 1 narg=$((narg - 1)) ;; esac done # 测试输出所有匹配的src路径 printf '匹配到的src路径共%d个:\n' "${#src[@]}" printf ' - %s\n' "${src[@]}" return }
注意事项
- 如果你需要把通配符本身传给脚本、不提前展开,调用时需要把路径用引号包裹:
rando -s "/angio/repo/A*",此时可以在脚本内通过glob或者compgen手动完成通配符展开 - 所有变量、数组赋值必须加双引号,避免文件名带空格、特殊字符时解析错误
- 不要随意修改IFS处理参数,手动按规则移位或者使用内置
getopts解析更稳妥
内容的提问来源于stack exchange,提问作者Angio
相关产品推荐
相关产品推荐

