You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash脚本中无eval扩展含特殊字符的Glob变量为数组

解决Bash中带空格/引号的Glob模式扩展问题

你的核心问题在于直接用files=($glob)会忽略引号,把空格当成分隔符,导致带空格的文件名被拆分成多个项,同时无法正确解析带引号的模式。而且由于模式是从文件读取的,没法直接写进数组字面量里。这里有个不用eval的安全方案,分两步处理:先正确拆分带引号的模式项,再逐个扩展Glob。

改造后的核心代码

直接替换你原循环里的files=($glob)部分,完整修改后的代码如下:

template_include_pat='^#include (.*)$'
# 提前开启nullglob,确保无匹配的模式不会留下空字符串
shopt -s nullglob

while IFS='' read -r line || [[ -n "$line" ]]; do
    if printf '%s' "$line" | grep -qE "$template_include_pat"; then
        glob=$(printf '%s' "$line" | sed -nrE "s/$template_include_pat/\\1/p")
        cwd=$(pwd -P)
        cd "$targetdir"
        
        # 关键步骤1:拆分带引号的模式为单独的项(保留带空格的文件名)
        # 用xargs解析引号,把被包裹的内容当成单个项输出
        IFS=$'\n' read -r -d '' -a patterns < <(printf '%s\n' "$glob" | xargs -d '\n' printf '%s\n')
        
        # 关键步骤2:逐个扩展每个模式,收集到files数组
        files=()
        for pat in "${patterns[@]}"; do
            files+=($pat)
        done
        
        # 后续处理逻辑不变
        for f in "${files[@]}"; do
            printf "\n\n%s\n" "# FILE $f" >> "$tempfile"
            cat "$f" >> "$tempfile" || die "Cannot read '$f'."
        done
        cd "$cwd"
    else
        echo "$line" >> "$tempfile"
    fi
done < "$template"

# 用完后关闭nullglob,避免影响其他逻辑
shopt -u nullglob

为什么这个方案可行?

  • 模式拆分:xargs -d '\n' printf '%s\n'会自动解析输入字符串中的引号(单/双引号)和反斜杠,把"dir/file with spaces"这类带空格的内容当成单个模式项输出,而不是拆分成三个部分。
  • 安全扩展:对每个拆分后的模式单独进行Glob扩展,结合nullglob选项,没有匹配的模式会被直接忽略,不会留下空元素。
  • 避免eval风险:eval虽然能解析引号,但如果模板文件里的模式被注入恶意代码(比如$(rm -rf /)),会直接执行,这个方案完全规避了这个安全问题。

兼容性说明

如果是在BSD系统(比如macOS)上,xargs的-d选项是GNU扩展,不可用,可以用下面的替代方式拆分模式:

# BSD xargs兼容的拆分方式
IFS=$'\n' read -r -d '' -a patterns < <(printf '%s\0' "$glob" | xargs -0 -n1 printf '%s\n')

原代码的问题根源

files=($glob)是无引号的变量展开,Bash会按照IFS(默认是空格、制表符、换行)拆分字符串,完全忽略引号的存在。比如"dir/file with spaces"会被拆成"dir/file"、with、spaces"三个无效的文件名,自然会出错。

内容的提问来源于stack exchange,提问作者steiny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:30:36