BASH: Writing a Script to Recursively Travel a Dir

2019-01-17 18:12发布

问题:

I have the following directory structure for example:

/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/ )

I've written the following bash script that effectively travels to the second level of /test_dir so it will reach /test_dir/d/cron or /test_dir/tree/a but will not go further. I cannot figure out why the recursive script will not travel further can someone please debug the script and point out my error?

here is what I have written:

#!/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

here is the output:

/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

I know there are probably more elegant one line commands to do this. But im trying to do it in this explicit manner. I apologize for the length of this post.

EDIT: using traverse "${1}/${file}"

回答1:

Several problems with the script. It should be like this:

#!/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"

However, the correct way to recursively traverse a directory is by using the find command:

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


回答2:

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

These are the errors. Some which are not only not directories but do not exist are considered files. I think you need to separate your new files from the directory with slash:

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

And also check that they do exist as well.

Since you're using bash as well, I'd suggest this form instead:

#!/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 "$@"

You can run the script with multiple arguments.

A fixed version of your script:

#!/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"