Search code examples
bashprintingdirectory

Script unable to differ between subdirectories and files


I am writing a bash script to print all the files in a directory. If there is a subdirectory, then expand it and print all the file in it also. This is a recursive process I have handled with the following code:

#!/bin/bash

#lsall -> list all the file in a directory and sub directory

print_dir_content(){
        echo -e "\nIn $1: (DIRECTORY)\n"
        for i in `ls $1`; do
                if ! [ -d $i ]; then
                        echo -e "F\t$i"
                else
                        print_dir_content $i
                fi
        done
}

if [ $# -lt 1 ]; then
       echo "Usage: $0 [DIR]"
       exit
else
        DIR="$1"
fi

if ! [ -d $DIR ]; then
        echo "Usage: $0 [DIR]"
        exit
fi

echo -e "\nIn $DIR:\n"
for i in `ls $DIR`; do
        echo "$i"
        if [ -d $i ]; then
                print_dir_content $i
        else
                echo -e "F\t$i"
        fi
done

The script runs with no errors though, subdirectories are seen as files and the recursive function cannot print the content of the inner directory. Since I am new to bash but not to programming, is this some language problem that I am facing, or it's a logical one? Thanks in advance.


Solution

  • Your code does not do cd but the ls output is a relative path. A non-existent file cannot be a directory so the file branch will be taken. (Unless the top-level has a directory with the same name, in which case you'll end up in an infinite loop.)

    #!/bin/bash
    
    print_dir_content()(
        echo -e "\nIn $1: (DIRECTORY)\n"
        cd "$1" || exit
        for i in *; do
            if [ -d "$i" ]; then
                print_dir_content "$i"
            else
                echo -e "F\t$i"
            fi
        done
    )
    
    dir=$1
    if ! [ -d "$dir" ]; then
        echo "Usage: $0 [DIR]"
        exit
    fi
    
    print_dir_content "$dir"
    
    • parsing ls output is considered bad practice
    • your final loop is just the recursive function (you can parameterise if you want to retain the different message)
    • (...) spawns a subshell; alternatively you can cd .. at the end of the function (bash also has pushd/popd)
      • I just abort the function if cd failed; you could print a message or do other handling
    • variable use should usually be quoted to avoid word-splitting
    • ALLCAPS variable names are reserved for use by the shell
    • zero-length names cannot exist so you can simplify the sanity checks
    • you'll need slightly more complicated code if you want to list files/directories whose names begin with .

    I'm assuming this is for learning; find or ls -R already allow recursive listing.