This question already has an answer here:

I have this:

#!/bin/bash

for file in `find . -type d`
do
  echo $file
done

If I have just one directory called My Directory, the output is

My
Directory

How do I fix this?

The echo $file is just temporary. There will be other code in there operating on the directories.

marked as duplicate by jasonwryan, Gilles bash Jan 10 '15 at 21:51

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.

up vote 4 down vote accepted

Something like the following works ...

find . -type d | while read dir; do echo $dir; done
.
./my dir

Depending on what you're doing, you might be better using find's -print0 option and xargs -0.

The code you've got takes the unquoted output from find and uses it as a list of words (split on whitespace) for for to iterate over.

Do not use for loop, use while instead:

find . -type d -print0 | while read -d '' -r dir; do echo "$dir"; done

Option print0 prints NULL character at the end of file/directory name (instead of newline) and read -d '' interprets it properly.

  • 2
    This assumes that you use GNU find of BSD find. – cuonglm Jan 10 '15 at 16:20

If you're really just looking to echo the results of find, you can use the parameter -print (or just no additional parameter at all) to have find print a list of its results.

If you want to delete the results, there's -delete (which can be combined with -print to get a list of the deleted files).

If you want to do something else with/to the results, you can use the parameter -exec to pass the results as parameters to another command, e.g.

  • find . -type d -exec tar cf {}.tar {} \; to compress all directories into individual tarballs (one tar per directory, since \; makes find run the -exec command with one result at a time)
  • find . -type d -exec tar cf all-directories.tar {} + to compress all directories into a single tarball (+ makes find run the -exec command with as many results as possible at a time)
  • I'll be doing an xattr to remove resource forks on OSX with this. Question edited, thanks. – Almo Jan 10 '15 at 16:13
  • Maybe it would be a good idea to issue a warning about -delete! Like deltree on DOS prompt in Windows, this seemingly inconspicuous option can cause huge file trees to get purged in no time!! So use -delete with extreme caution. – syntaxerror Feb 7 '15 at 13:01

Before answering your answer, I highly recommend you reading two question:

For your question, you don't need a for loop, just find itself:

find -type d

If you want to do more things, just use -exec option (or -execdir if your find support):

find -type d -exec ... +
  • Just to make one thing clear: for the OP's question, the for loop is indeed unnecessary BUT ... it is not necessarily redundant, especially not for bash beginners. For example, if you use two loop variables i and j (with j being an altered i) or simply a couple different statements, the for loop approach (though frowned upon) is easier to comprehend than teaching them the pro solution of -exec sh -c ... which is as if you attempted to teach calculus to a person that only ever learned about basic arithmetics. – syntaxerror Apr 28 '15 at 1:23

You can just use "$file" in your example.

  • 1
    This doesn't actually work. The for breaks it up before it gets there. – Almo Jan 10 '15 at 16:10
  • What do you mean breaks it up? Using echo "$file" works for me. – adamantly Jan 10 '15 at 16:16
  • Echo "$file" works on one variable. But in this loop, the for $file has already broken the output of the find command in to a list of strings that were split by spaces. So it's too late already by the time it gets to the echo command. – Almo Jan 10 '15 at 19:58

You have to set IFS variable in bash:

SAVEIFS=IFS
IFS=$(echo -en "\n\b")
...
YOURCODE
....
IFS=$SAVEIFS

But what does above code do? , it discard any space and meta char..

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