bash中如何正确使用包含星号*的路径变量?
解决方案
前提说明
星号通配符展开分为两个阶段:
- 命令行传参阶段:如果用户执行脚本时没有用单引号包裹带
*的参数(例如直接写./your_script.sh /home/*),*会在脚本启动前就被shell展开为具体路径,脚本无法获取原始带星号的参数。因此要求用户传带通配符的参数时必须用单引号包裹:./your_script.sh '/home/*' - 脚本内部解析阶段:未加引号的变量调用会触发shell二次展开,这是现有代码的核心问题。
代码修正方案
1. 参数接收部分修正
原有代码有两个错误:未给$@加引号导致展开、数组追加语法错误,不需要循环,直接一行就能正确接收所有参数且保留原始字符:
#!/bin/bash # 直接接收所有参数存入数组,双引号保证参数原样保留不展开 dir=("$@")
如果一定要用循环实现,写法如下:
dir=() for i in "$@"; do dir+=("$i") done
2. 逻辑判断部分修正
原有${dir[*]}未加引号会触发展开,遍历数组必须用"${dir[@]}"才能保留每个元素的原始值:
for i in "${dir[@]}"; do # 判断参数包含星号的逻辑保持不变 if [[ "$i" == *"*"* ]]; then # 给$i加引号避免shell提前展开星号,交给find处理通配符匹配 find "$i" -maxdepth 1 -type d fi done
备选方案:临时关闭通配符展开
如果需要避免脚本内部任何位置的通配符展开,可以在脚本开头开启noglob选项,关闭路径通配符解析功能:
#!/bin/bash # 关闭通配符展开 set -o noglob # 后续所有变量调用都不会触发*展开,代码可以不用额外加引号处理 dir=("$@") for i in "${dir[@]}"; do if [[ "$i" == *"*"* ]]; then find $i -maxdepth 1 -type d fi done # 可选:处理完成后恢复通配符展开 set +o noglob
注意:该方案只能避免脚本内部的展开,依然要求用户传参时用单引号包裹带
*的参数。
内容的提问来源于stack exchange,提问作者Jörg Kauke
相关产品推荐
相关产品推荐

