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

Bash脚本遍历目录时文件路径重复添加至数组问题排查

脚本重复添加文件至数组的问题排查

问题场景

使用macOS + bash 4(Homebrew安装)开发脚本,目标是遍历指定路径下所有文件存入数组,但测试时发现3级子目录中的foo.file仅存在一次,却被重复添加4次。

目录结构

.
├── fetchProjects.sh
├── foo
│   └── bar
│       └── buzz
│           └── foo.file
├── test1
└── test2

脚本代码

#!/opt/homebrew/bin/bash

declare -a files=()

fetch_folder_content () {
    echo "Current path is: $1"
    subfolders="$(ls $1)"
    echo "Relative paths are: $subfolders"
    for subfolder in $subfolders; do
        declare -a subfolders=()
        this_path="$1/$subfolder"
        echo "This path: $this_path"
        if test -d $this_path; then
            fetch_folder_content $this_path
        fi
        if test -f $this_path; then
            echo "Appending $subfolder
     to array"
            files[${#files[@]}]=$this_path
        fi
    done
}

fetch_folder_content "."

echo "Found files:"
for file in "${files[@]}"; do
    echo "$file"
done

脚本输出

Found files:
./fetchProjects.sh
./foo/bar/buzz/foo.file
./foo/bar/buzz/foo.file
./foo/bar/buzz/foo.file
./foo/bar/buzz/foo.file
./test1
./test2

原因分析

核心问题是循环迭代变量与内部定义的数组变量重名,导致变量类型被意外覆盖:

  • 外层用subfolders变量存储ls输出的字符串结果,作为循环的迭代列表;但在循环内部又执行declare -a subfolders=(),将同名变量重新定义为空数组。
  • bash中字符串变量与数组变量共享命名空间,这种重名操作会直接破坏外层的循环迭代列表。递归调用返回后,原本的字符串变量已经变成数组类型,后续循环迭代逻辑混乱,最终导致同一个文件被多次遍历添加。

另外,用ls获取目录内容本身存在风险——若文件名包含空格或特殊字符,会被错误拆分,这是潜在的兼容性问题,但本次重复添加的直接根源是变量重名导致的迭代逻辑异常。

修复方案

  1. 消除变量重名:删除循环内无意义的declare -a subfolders=()定义(该数组未被使用),或重命名为不冲突的变量名。
  2. 替换ls的不安全用法:用bash原生的glob遍历("$1"/*),避免文件名拆分错误,同时支持含空格的文件名。
  3. 优化条件判断:用[[ -d "$path" ]]、[[ -f "$path" ]]替代test,语法更安全,支持带空格的路径。

修复后的示例脚本:

#!/opt/homebrew/bin/bash

declare -a files=()

fetch_folder_content () {
    local current_path="$1"
    # 用glob遍历当前目录下的所有项
    for item in "$current_path"/*; do
        # 跳过目录为空时的glob占位符
        [[ -e "$item" ]] || continue
        if [[ -d "$item" ]]; then
            fetch_folder_content "$item"
        elif [[ -f "$item" ]]; then
            # 直接用+=语法向数组添加元素,更简洁
            files+=("$item")
        fi
    done
}

fetch_folder_content "."

echo "Found files:"
for file in "${files[@]}"; do
    echo "$file"
done

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:56:21