Search code examples
bashloops

Looping on empty directory content in Bash


I'm writing a shell script in which I need to loop over directories and then loop over files inside them. So I've written this function:

loopdirfiles() {
    #loop over dirs
    for dir in "${PATH}"/*
    do
        for file in "${dir}"/*
            do
                echo $file
            done
    done
}

The problem is that it echoes something like path/to/dir/* on empty directories.

Is there a way to use this approach and ignore those kind of directories?


Solution

  • You can cut the * from the directory name instead of completely ignoring it:

    [[ $file == *"*" ]] && file="${file/%\*/}"
    #this goes inside the second loop
    

    Or if you want to ignore the empty directory:

    [[ -d $dir && $ls -A $dir) ]] || continue
    #this goes inside the first loop
    

    Another way:

    files=$(shopt -s nullglob dotglob; echo "$dir"/*)
    (( ${#files} )) || continue
    #this goes inside the first loop
    

    Or you can turn on the nullglob (mentioned by Etan Reisner) and dotglob altogether:

    shopt -s nullglob dotglob
    #This goes before first loop.
    


    From Bash Manual

    nullglob

    If set, Bash allows filename patterns which match no files to expand to a null string, rather than themselves.

    dotglob

    If set, Bash includes filenames beginning with a ‘.’ in the results of filename expansion.

    Note: dotglob includes hidden files (files with a . at the beginning in their names)