BASH: 编写递归遍历N级目录的脚本

20

我有以下示例的目录结构:

/test_dir/d
/test_dir/d/cron
/test_dir/d/cache
/test_dir/d/...(more sub dirs)
/test_dir/tree
/test_dir/tree/a
/test_dir/tree/a/a1
/test_dir/tree/a/a2
...(and so on for b/ and c/ )

我写了下面这个 bash 脚本,它可以有效地进入到 /test_dir 的第二级目录,以便可以到达 /test_dir/d/cron/test_dir/tree/a,但不会进一步前往。我无法弄清楚为什么递归脚本不能继续前进,可以有人帮忙调试脚本并指出我的错误吗?

这是我编写的内容:

#!/bin/bash

#script to recursively travel a dir of n levels

function traverse() {   

for file in `ls $1`
do
    #current=${1}{$file}
    if [ ! -d ${1}${file} ] ; then
        echo " ${1}${file} is a file"
    else
        #echo "entering recursion with: ${1}${file}"
            traverse "${1}/${file}"
    fi
done
}

function main() {
    traverse $1
}

main $1

这是输出结果:

/test_dir/a is a file
/test_dir/b is a file
/test_dir//dcache is a file
/test_dir//dcron is a file
/test_dir//dgames is a file
/test_dir//dlib is a file
/test_dir//dlog is a file
/test_dir//drun is a file
/test_dir//dtmp is a file
/test_dir/movies is a file
/test_dir//treea is a file
/test_dir//treeb is a file
/test_dir//treec is a file
/test_dir//treed is a file

我知道可能有更优雅的一行命令来完成这个任务。但我尝试以这种明确的方式来完成。对于这篇文章的长度,我感到抱歉。

编辑:使用traverse "${1}/${file}"

2个回答

43

脚本存在几个问题,应该这样写:

#!/bin/bash

#script to recursively travel a dir of n levels

function traverse() {
for file in "$1"/*
do
    if [ ! -d "${file}" ] ; then
        echo "${file} is a file"
    else
        echo "entering recursion with: ${file}"
        traverse "${file}"
    fi
done
}

function main() {
    traverse "$1"
}

main "$1"

然而,递归遍历目录的正确方法是使用find命令:

find . -print0 | while IFS= read -r -d '' file
do 
    echo "$file"
done

“-f” 代替 “! -d” 行不行?你是想检测一个文件对吧? - XChikuX
@XChikuX 没错,那部分是从原帖的代码中复制过来的。 - user000001

3
/test_dir/treea is a file
/test_dir/treeb is a file
/test_dir/treec is a file
/test_dir/treed is a file

以下是错误信息。其中一些不仅不是目录,而且不存在,被认为是文件。我认为你需要用斜杠将新文件与目录分开:

    traverse "${1}/${file}"

并且要确保它们确实存在。

既然您也在使用bash,我建议使用以下方式:

#!/bin/bash

shopt -s dotglob  ## Optionally would allow matches for directories beginning with .
shopt -s nullglob

function traverse {
    local a file
    for a; do
        for file in "$a"/*; do
            if [[ -d $file ]]; then
                traverse "$file"
            else
                echo " $file is a file."
            fi
        done
    done
}

traverse "$@"

您可以使用多个参数运行脚本。

修复后的脚本:

#!/bin/bash

#script to recursively travel a dir of n levels

function traverse() {   
    for file in $(ls "$1")
    do
        #current=${1}{$file}
        if [[ ! -d ${1}/${file} ]]; then
            echo " ${1}/${file} is a file"
        else
            #echo "entering recursion with: ${1}${file}"
            traverse "${1}/${file}"
        fi
    done
}

function main() {
    traverse "$1"
}

main "$1"

谢谢。我尝试了你的建议,但问题仍然存在。我会编辑帖子,这样你就可以看到更改了。 - user800786
你还应该在检查中添加 / :if [ ! -d ${1}/${file} ] ; then,并在下一行 echo " ${1}/${file} 是一个文件" - konsolebox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接