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获取目录内容本身存在风险——若文件名包含空格或特殊字符,会被错误拆分,这是潜在的兼容性问题,但本次重复添加的直接根源是变量重名导致的迭代逻辑异常。
修复方案
- 消除变量重名:删除循环内无意义的
declare -a subfolders=()定义(该数组未被使用),或重命名为不冲突的变量名。 - 替换
ls的不安全用法:用bash原生的glob遍历("$1"/*),避免文件名拆分错误,同时支持含空格的文件名。 - 优化条件判断:用
[[ -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
相关产品推荐
相关产品推荐

