在find命令中使用通配符与正则表达式并避免Bash通配符展开
问题解决方法
1 通配符意外展开的原因和修复
你遇到的通配符被提前展开为当前目录文件名的问题,核心是两处写法错误:
- 函数内部
set -- $*未加引号:无引号包裹的$*会触发Bash的路径名展开机制,直接把通配符替换为当前目录下匹配的文件/目录名,你得到的Admir就是这一步展开的结果。 - 原find命令未给变量加引号:
find $dir -name $nm的写法中,$nm无引号包裹,就算前面参数没有展开,到这一步也会触发路径名展开。
以下是修正后的函数代码,直接基于原始参数解析,不需要修改IFS,从根源避免通配符提前展开:
mse () { local incl=() local dir="" # 直接遍历原始参数,避免触发通配符展开 while (( $# > 0 )); do case "$1" in -d) dir="$2"; shift 2 ;; --incl=*) incl+=("${1#*=}"); shift 1 ;; # 直接截取等号后内容,不需要额外拆分 --incl) incl+=("$2"); shift 2 ;; *) shift 1 ;; # 其余参数可根据需求自行扩展处理 esac done echo "incl: ${incl[@]}" # 调用find的正确写法,变量全部加双引号,通配符直接传给find自身处理 for pattern in "${incl[@]}"; do find "$dir" -name "$pattern" done }
调用时只要用引号包裹通配符参数即可,两种写法都生效:
# 双引号包裹参数 mse -d /media/hag/hc1/a1-chaos/amvib/ --incl="A*" # 单引号包裹更稳妥,完全避免Bash调用阶段展开通配符 mse -d /media/hag/hc1/a1-chaos/amvib/ --incl='A*'
2 find结合正则表达式的构造方法
find自带-regex参数支持正则匹配,使用时注意以下规则:
-regex默认匹配文件的完整路径,不是仅匹配文件名,如果只需要匹配文件名部分,需要在正则前缀加.*\/匹配路径的前置部分- 可通过
-regextype指定正则语法,常用posix-extended启用扩展正则,不需要额外转义+、()等元字符 - 用
-iregex可实现忽略大小写的正则匹配
举个实际示例,比如要匹配目标路径下所有文件名以A开头、包含数字、后缀为.md的文件:
# 使用扩展正则,仅匹配文件名部分符合规则的文件 find "$dir" -regextype posix-extended -regex '.*/A[0-9]+.*\.md'
如果需要把你的函数改为支持传入正则,只需要替换find的匹配参数即可:
for regex_pattern in "${incl[@]}"; do find "$dir" -regextype posix-extended -regex "$regex_pattern" done
内容的提问来源于stack exchange,提问作者Nigel
相关产品推荐
相关产品推荐

