2

This question already has an answer here:

Currently, I am trying to parse out all the files inside a directory. I have a find function, but it appears to not be able to parse in file directories with whitespaces into a loop. Here, "$DIR" is the directory I wish to search in. Does anyone have any ideas how I can modify it to work? thanks.

for file in $(find "$DIR" -type f)
do
   echo "$file"
done

marked as duplicate by ilkkachu bash Jun 8 '18 at 20:31

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

5

You don't need to for loop this.

find "$dir" -type f

will by default output all found objects.

You can make this explicit with:

find "$dir" -type f -print

If you really want to iterate over these, use a null separator and xargs:

find "$dir" -type f -print0 | xargs -0 -n1 echo

Or find's own -exec:

find "$dir" -type f -exec echo "{}" \;
  • If I wanted to pass the filenames found into a function, is there a standard way to do it? – user321627 Jun 8 '18 at 17:49
  • I'd read the results of find into an array (arr=( $( find [...] ) )), and reference that array within the function, or pass its contents to the function func "${arr[@]}". – DopeGhoti Jun 8 '18 at 17:52
  • 1
    @DopeGhoti isn't that going to have the same word-splitting issues as the original? See for example How to pass files found by find as arguments? – steeldriver Jun 8 '18 at 19:18
  • Yeah, probably. Let me revise. I'd probably pass the directory to the function, and let it handle the finding. – DopeGhoti Jun 8 '18 at 21:49
5

find ... | xargs ... and find ... -exec ... are both better options than this: to use a shell loop to iterate over find results correctly, we must use a while read loop:

while IFS= read -d '' -r filename; do 
    echo "$filename"
done < <(find "$dir" -type f -print0)

A lot to unpack there:

  • we use a Process Substitution to execute the find command and be able to read from the results like it's a file.
  • To read a line of input verbatim, the bash idiom is IFS= read -r line. That allows arbitrary whitespace and backslashes to be read into the variable.
  • read -d '' uses the null byte (as produced by -print0) as the end-of-line character instead of newline.
4

You should not parse the output of find for the same reasons you shouldn't parse ls

Try using find/exec instead:

find "$DIR" -type f -exec echo {} \;

Not the answer you're looking for? Browse other questions tagged or ask your own question.