递归bash函数(目录迭代器)

时间:2016-10-17 00:31:55

标签: bash unix recursion

我知道我可以使用更简单的“找到”来完成以下任务。评论,但我试图使用递归调用实现解决方案。我正在查看特定目录并尝试获取所有子目录中任何文件名的最大长度。但是,我的递归只能降低一级,所以它基本上会返回某个目录或其中的最长文件名。子目录。

#! /bin/bash

export maxlen=0

findmaxr()
{
        if [ $# -eq  0 ] ; then
        echo "Please pass arguments. Usage: findmax dir"
        exit -1
        fi

        if [ ! -d "$1" ];       then
        echo "No such directory exist."
        exit -2
        fi

        for file in $(/bin/ls $1)
                do
                if [ -d "$file" ] ; then
                        findmaxr $file   # Recursively call the method for subdirectories
                else
                        cur=${#file}
                        if [ $maxlen -lt $cur ] ; then
                                maxlen=$cur
                        fi
                fi
                done

        echo "The file with the longest name has [$maxlen] characters."



}

findmaxr `pwd`

2 个答案:

答案 0 :(得分:2)

这里有几个问题。最大的是[ -d "$file" ]findmaxr $filefile变量只包含文件的名称,而不是整个路径。所以,如果你在/ dir中,并且/ dir / sub / sub2存在,那么顶级将运行findmaxr /dir(这很好),它将运行findmaxr sub(这是有效的,但不是'真的是你想要的),然后运行findmaxr sub2(根本不起作用)。因此,一种可能性是在这些行中使用"$1/$file",但还有另一个问题:parsing ls is a bad idea and will fail for some directory names。最好使用没有解析问题的for path in "$1"/*(前提是你引用了所有变量引用,无论如何都要引用它)为你提供了完整的路径,所以你不必预先$1/。但是,在检查文件名长度之前,你必须剥离路径的前面,例如local file="$(basename "$path")"

第二个问题是它在完成每个目录后打印$maxlen,而不是在扫描整个树之后。要解决此问题,只需在运行findmaxr后将该命令从递归函数移出到主序列。

还有另一个更微妙的问题:filecurpath如果你遵循我的建议)不是局部变量,这意味着递归调用可以改变它们的值而不是调用findmaxr的实例。您应该将它们声明为局部变量以避免混淆。哦,没有必要导出maxlen - 它将自动在脚本中全局,并且它与您正在运行的任何命令无关(export将其传递给它)。

答案 1 :(得分:2)

findmaxr的每个实例都需要返回它找到的maxlen(通过echo),你需要在比较中包含该输出。

还有另一个问题:假设abc是目录,d.txt是一个文件,它们按如下方式排列:{{1} }。从a/b/c/d.txt内部运行脚本。当afile时,b为真,if [ -d "$file" ]被调用。它会调用findmaxr b,而ls b会导致findmaxr c,导致ls c ... ls c失败,因为您仍然在a。你需要cd到子目录或者包括整个路径,如下所示:$1/$file

这是修复了这些问题的脚本:

#!/bin/bash

findmaxr()
{
    if [ $# -eq  0 ] ; then
    echo "Please pass arguments. Usage: findmax dir"
    exit -1
    fi

    if [ ! -d "$1" ];       then
    echo "No such directory exist."
    exit -2
    fi

    maxlen=0
    for file in $(/bin/ls "$1")
            do
            if [ -d "$1/$file" ] ; then
                    cur=`findmaxr "$1/$file"`   # Recursively call the method for subdirectories
            else
                    cur=${#file}
            fi
            if [ $maxlen -lt $cur ] ; then
                maxlen=$cur
            fi
        done
        echo $maxlen
}

maxlen=$(findmaxr $(pwd))
echo "The file with the longest name has [$maxlen] characters."