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

Bash递归函数无法深层遍历求助:为何同事的版本可行?

为什么我的Shell递归遍历目录脚本只能处理第一层级?

我最近写了个Shell脚本,想统计指定文件夹下的隐藏文件、符号链接和子目录总数,但递归函数只能遍历第一层级的目录,深层目录根本处理不了。我自己的代码是这样的:

function recursive_func() {
    current=$1
    echo $current
    for thing in $(ls -A $current)
    do
        if [ -d $current/$thing ]
        then
            let subd++
            recursive_func $current/$thing
        elif [ -L $thing ] ; then
            let symlinks++
        elif [ -f $thing -a ${thing:0:1} == "." ] ; then
            let hidden++
        fi
    done
}

好在同事给了一个能正常工作的版本:

function recursive_func() {
    echo $1
    for thing in $(ls -A $1)
    do
        path=$1/$thing
        if [ -d $path ]
        then
            let subd++
            recursive_func $path
        elif [ -L $path ] ; then
            let symlinks++
        elif [ -f $path -a ${thing:0:1} == "." ]; then
            let hidden++
        fi
    done
}

一开始我完全搞不懂两者的差异在哪,后来才发现问题出在变量作用域和路径完整性两个地方:

1. 全局变量被递归调用破坏

我的代码里,current=$1没有加local修饰,所以current是一个全局变量。当第一次调用函数处理根目录时,current被设为根目录路径;但当递归处理子目录时,current会被覆盖成子目录的路径。等递归返回回到上层循环时,current已经不是原来的根目录了,后续循环处理的$current/$thing全是错误的路径,自然没法继续遍历上层目录的其他内容。

而同事的代码根本没用到全局变量,直接用函数的参数$1表示当前目录,拼接完整路径时用$1/$thing,递归调用也直接传拼接好的$path——完全不会因为递归调用破坏上层的上下文。

2. 文件类型判断用了错误的路径

我的代码里判断符号链接和普通文件时,用的是$thing而不是$current/$thing。$thing只是当前目录下的文件名,Shell会在当前工作目录下去找这个文件,而不是我们正在遍历的$current目录,这会导致很多判断结果完全错误。比如当遍历子目录时,$thing是子目录里的文件名,但我们的工作目录还是上层目录,[ -L $thing ]肯定找不到对应的文件。

同事的代码里用了完整路径$path(也就是$1/$thing)来做判断,确保每次都是检查目标目录下的对应文件,判断结果准确。

修复我的代码的两种方式

方式一:给current加上local修饰,同时修正路径判断

function recursive_func() {
    local current=$1  # 把current变成函数局部变量,避免递归修改
    echo $current
    for thing in $(ls -A $current)
    do
        full_path="$current/$thing"  # 统一用完整路径
        if [ -d "$full_path" ]
        then
            let subd++
            recursive_func "$full_path"
        elif [ -L "$full_path" ] ; then
            let symlinks++
        elif [ -f "$full_path" -a "${thing:0:1}" == "." ] ; then
            let hidden++
        fi
    done
}

方式二:直接参考同事的写法,依赖函数参数而非全局变量

就像同事的代码那样,全程用$1表示当前目录,拼接完整路径后做判断和递归,从根源避免全局变量的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 00:03:12