10

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?

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
lerp90
  • 503
  • 8
  • 23
  • 3
    If you are using `PATH` as a variable in your script **don't**. You will break running external commands as `PATH` is used for that. In general ALL_CAPS variables should be avoided (other than for script globals) as they are "reserved" for the shell's/etc. use. – Etan Reisner May 05 '15 at 02:44

2 Answers2

11

You can turn on the nullglob option. It causes unmatching globs to expand to an empty list instead of being left unexpanded.

shopt -s nullglob
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • I've set this option outside of the function and gave me the same result. – lerp90 May 05 '15 at 02:31
  • 1
    Make sure you are using `bash` and not `sh` and make sure you set that in the same shell session that you expect to use it (e.g. setting it in your current shell and then running a script with that function won't see it). – Etan Reisner May 05 '15 at 02:37
2

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)

Community
  • 1
  • 1
Jahid
  • 21,542
  • 10
  • 90
  • 108