views:

74

answers:

5

I find myself frequently doing the following:

for f in `find -foo -bar -baz`; do
  process "$f"
done

This of course doesn't work for file names with spaces. How can I handle such cases?

+2  A: 
find . -type f | while read file; do 
     process "$f"
done;
Drakosha
This is *exactly* what I needed. Thanks!
AdSR
"$f" should be "$file". Use `while read -r` to take of literal backslash in file names
ghostdog74
A: 

In such cases, my approach is to build the list before the for command and replace whitespace inside element names by another character or string which is unlikely to appear.

Then inside the loop, I replace back that specific string by a whitespace.

An example:

list=`find -foo -bar -baz | tr ' ' 'µ'`
for fx in $list ; do
    f=`echo $fx | tr 'µ' ' '`
    process "$f"
done
mouviciel
This is verbose and not robust.
Charles Stewart
+1  A: 

If you are using find already, why not simply use exec

find -foo -bar -baz -exec process '{}' \;

The alternative solution would be to change the IFS variable (inter field seperator)

amo-ej1
+3  A: 

Find and xargs work well together. find can print the names of the files with a \0-delimiter (option print0) and xargs can read them in that format (option -0):

find . -type f -print0 | xargs -0 echo
soulmerge
Don't forget xargs! On lists of very large numbers of files, you may find yourself getting the dreaded "Too many arguments" error. These two O'Reilly articles explain the situation: http://linuxdevcenter.com/pub/a/linux/lpt/09_21.html http://linuxdevcenter.com/pub/a/linux/lpt/09_22.html
Jim
+1  A: 

bash 4

shopt -s globstar
for file in /path/**
do
  process "$file"
done
ghostdog74