Recursively iterate through files in a directory

Doing this is as simple as:

find -exec sh -c 'inline script "$0"' {} \;

Or...

find -exec executable_script {} \;

Yet another use for safe find:

while IFS= read -r -d '' -u 9
do
    [Do something with "$REPLY"]
done 9< <( find . -type f -exec printf '%s\0' {} + )

(This works with any POSIX find, but the shell part requires bash. With *BSD and GNU find, you can use -print0 instead of -exec printf '%s\0' {} +, it will be slightly faster.)

This makes it possible to use standard input within the loop, and it works with any path.


The simplest (yet safe) approach is to use shell globbing:

$ for f in *; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
h:

To make the above recurse into subdirectories (in bash), you can use the globstar option; also set dotglob to match files whose name begins with .:

$ shopt -s globstar dotglob
$ for f in **/*; do printf ":%s:\n" "$f"; done 
:a b:
:c
d:
:-e:
:e  f:
:foo:
:foo/file1:
:foo/file two:
h:

Beware that up to bash 4.2, **/ recurses into symbolic links to directories. Since bash 4.3, **/ recurses only into directories, like find.

Another common solution is to use find -print0 with xargs -0:

$ touch -- 'a b' $'c\nd' $'e\tf' $'g\rh' '-e'
$ find . -type f -print0 | xargs -0 -I{} printf ":%s:\n" {}
h:/g
:./e    f:
:./a b:
:./-e:
:./c
d:

Note that the h:/g is actually correct since the file name contains a \r.