如何从sh向bash脚本传递ext glob并实现正确展开?
如何在Bash脚本中正确处理传递的大括号扩展/Extglob模式
问题原因
你遇到的问题核心在于:
- 当用引号包裹
"{a,1}*.txt"传递时,当前Shell不会执行大括号扩展(这是Bash的参数扩展特性,不属于glob匹配);脚本中变量展开后,Bash也不会回溯处理这个字符串的大括号扩展,只会把它当作一个字面文件名模式去匹配,自然找不到目标文件。 - 脚本里开启了
extglob但实际用的是大括号语法,两者是不同的Bash特性:extglob的语法是@(a|1)*.txt这类,而{a,1}*.txt属于大括号扩展。
解决方案
方案1:不使用引号传递参数(简单直接)
如果参数中没有空格或特殊字符,直接让当前Shell先完成大括号扩展,再把结果传给脚本:
./se.sh {a,1}*.txt
同时修改脚本,让它处理所有传入的参数(而不是仅第一个):
#!/bin/bash shopt -s nullglob # 若使用extglob语法则开启,大括号扩展不需要 # shopt -s extglob # 遍历所有传入的参数对应的文件 for f in a/path/to/all/files/"$@"; do echo "file process: ${f}" done shopt -u nullglob # shopt -u extglob
方案2:脚本内用eval解析带扩展的参数(适合必须用引号传递的场景)
如果必须用引号包裹参数(比如参数包含空格、特殊符号),可以用eval强制Bash重新解析变量内容,完成大括号扩展和glob匹配:
#!/bin/bash pattern="$1" shopt -s nullglob shopt -s extglob # 若用extglob语法则开启,大括号扩展可省略 # 用eval将模式与路径拼接后解析,结果存入数组 eval "target_files=(a/path/to/all/files/${pattern})" for f in "${target_files[@]}"; do echo "file process: ${f}" done shopt -u nullglob shopt -u extglob
执行命令:
./se.sh "{a,1}*.txt" # 若用extglob语法则执行:./se.sh "@(a|1)*.txt"
注意:
eval会执行字符串中的任意Shell命令,仅在参数来源可信时使用。
补充:区分大括号扩展与Extglob
- 大括号扩展:
{a,1}*.txt→ 先扩展为a*.txt和1*.txt,再做glob匹配 - Extglob:
@(a|1)*.txt→ 直接作为单个glob模式匹配以a或1开头的txt文件,需要开启shopt -s extglob
内容的提问来源于stack exchange,提问作者gfan
相关产品推荐
相关产品推荐

