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
.