Home » Questions » Computers [ Ask a new question ]

Making BASH script `for` handle filenames with spaces (or workaround)

Making BASH script `for` handle filenames with spaces (or workaround)

Whilst I have been using BASH for several years, my experience with BASH scripting is relatively limited.

Asked by: Guest | Views: 412
Total answers/comments: 5
Guest [Entry]

"You need to pipe the find into a while loop.

find ... | while read -r dir
do
something with ""$dir""
done

Also, you won't need to use -printf in this case.

You can make this proof against files with newlines in their names, if you wish, by using a nullbyte delimiter (that being the only character which cannot appear in a *nix filepath):

find ... -print0 | while read -d '' -r dir
do
something with ""$dir""
done

You will also find using $() instead of backticks to be more versatile and easier. They can be nested much more easily and quoting can be done much more easily. This contrived example will illustrate these points:

echo ""$(echo ""$(echo ""hello"")"")""

Try to do that with backticks."
Guest [Entry]

"The issue you're encountering is the for statement is responding to the find as separate arguments. The space delimiter. You need to use bash's IFS variable to not split on space.
Here is a link that explains how to do this.

The IFS internal variable
One way around this problem is to change Bash's internal IFS (Internal Field Separator) variable so that it splits fields by something other than the default whitespace (space, tab, newline), in this case, a comma.

#!/bin/bash
IFS=$';'

for I in `find -type d -printf \""%P\""\;`
do
echo ""== $I ==""
done

Set your find to output your field delimiter after the %P and set your IFS appropriately. I picked semi-colon since it's highly unlikely to found in your filenames.
The other alternative is to call mkdir from the find directly via -exec do you can skip the for loop altogether. That's if you don't need to do any additional parsing."
Guest [Entry]

find . -type d -exec mkdir -p "{}\040" ';' -exec echo "Created {}\040" ';'
Guest [Entry]

"or to make the whole thing much less complicated:

% rsync -av --include='*/' --exclude='*' SRC DST

this replicates the directory structure of SRC into DST."
Guest [Entry]

"If you have GNU Parallel http:// www.gnudotorg/software/parallel/ installed you can do this:

find . -type d | parallel echo making {} "";"" mkdir -p /tmp/outdir/{} "";"" echo made {}

Watch the intro video for GNU Parallel to learn more:
http://www.youtube.com/watch?v=OpaiGYxkSuQ"