5

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.

1
  • Or the SO variant
    – user60101
    Jan 10, 2015 at 20:04

6 Answers 6

5

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.

3

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.

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

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

3
  • 1
    This doesn't actually work. The for breaks it up before it gets there.
    – Almo
    Jan 10, 2015 at 16:10
  • What do you mean breaks it up? Using echo "$file" works for me.
    – adamantly
    Jan 10, 2015 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, 2015 at 19:58
1

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)
2
  • I'll be doing an xattr to remove resource forks on OSX with this. Question edited, thanks.
    – Almo
    Jan 10, 2015 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. Feb 7, 2015 at 13:01
1

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 ... +
1
  • 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. Apr 28, 2015 at 1:23
1

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 .