如何在Bash脚本中传递并解析通配符/正则匹配的文件参数
问题解答
你当前的传参方式存在两个核心问题:
- 通配符会被Shell提前展开为多个文件路径,你现有的参数解析逻辑只会将第一个匹配到的文件赋值给
src,其余路径会被识别为无效参数丢弃 - 匹配文件量过大时确实会触发系统
ARG_MAX参数长度限制,导致命令无法执行
以下是两种可直接落地的实现方案:
方案1:兼容Shell通配符自动展开逻辑(文件量不大时优先用)
修改参数解析逻辑,遇到-s选项后自动收集所有后续非-开头的参数作为源文件,直到碰到下一个选项或终止符--,符合常规命令的使用习惯:
#!/bin/bash src=() dst="" while (( $# > 0 )); do case "$1" in -s|--src|--source) shift # 批量收集所有源文件路径 while (( $# > 0 )) && [[ ! "$1" =~ ^- ]]; do src+=("$1") shift done ;; -d|--dst|--destin) dst="$2" shift 2 ;; --) shift break ;; -*) echo "Unknown option: $1" >&2 shift 1 ;; *) break ;; esac done # 参数校验后直接调用rsync,不需要循环 if [[ ${#src[@]} -gt 0 && -n "$dst" ]]; then rsync -av --update "${src[@]}" "$dst" else echo "缺少源文件或目标路径参数" >&2 exit 1 fi
方案2:支持直接传递通配符/正则(适配文件量极大的场景)
如果匹配文件量确实超出ARG_MAX限制,要求用户调用时用单引号包裹通配符避免Shell提前展开,脚本内部自行做路径匹配,完全规避参数长度限制:
用户调用示例:
mse -s '/media/hagbard/hc1/a1-chaos/amvib/A*' -d /target/path
脚本实现代码:
#!/bin/bash shopt -s nullglob # 匹配不到文件时返回空,不会把通配符本身作为结果 src_pattern="" dst="" while (( $# > 0 )); do case "$1" in -s|--src|--source) src_pattern="$2" shift 2 ;; -d|--dst|--destin) dst="$2" shift 2 ;; --) shift break ;; -*) echo "Unknown option: $1" >&2 shift 1 ;; *) break ;; esac done # 内部展开通配符 src=($src_pattern) if [[ ${#src[@]} -eq 0 ]]; then echo "未匹配到任何符合规则的源文件" >&2 exit 1 fi rsync -av --update "${src[@]}" "$dst"
如果需要支持正则规则匹配,可以把通配符展开逻辑替换为find命令实现:
# 示例:用find处理正则匹配,支持百万级文件无压力 src=() while IFS= read -r -d $'\0' file; do src+=("$file") done < <(find "$(dirname "$src_pattern")" -maxdepth 1 -type f -regex "$(basename "$src_pattern")" -print0)
内容的提问来源于stack exchange,提问作者Nigel
相关产品推荐
相关产品推荐

