Scripting Filenames with Spaces: A for Replacement

Okay, this will be a quickie. Really.

I use for loops in scripts all the time, but for chokes on files with spaces in the name. After years of finding ways to avoid this problem any way I could, I've finally found what I believe to be the solution.

The for command treats any whitespace as a line break. So if you try to use for on a list of files (or folders or whatever) the loop will not function properly on items with spaces in the name. The for command will treat everything after the space as a new item.

Let's say you want to copy every file that starts with "Systems" in the folder "Start" to a folder called "Finish." The "Start" folder contains the items:

Systems Boy

Systems Girl

Systems Baby

James Bond

Bat Man

Using for would go something like this:

for item in `ls Start | grep Systems`

   do cp "$item" Finish

done

The for command, however, will treat "Systems" and "Boy" as two separate items, and when the cp command is issued it will complain:

cp: Systems: No such file or directory

cp: Baby: No such file or directory

cp: Systems: No such file or directory

cp: Boy: No such file or directory

cp: Systems: No such file or directory

cp: Girl: No such file or directory

The solution is to forego for and pipe your command to a while read statement like in the following example:

ls Start | grep Systems | while read item

   do cp "$item" Finish

done

The quotes around the $item variable are essential. Without them the script will fail in the same way as for. With them, the script works like you wish the for loop did and is able to properly copy files with spaces in the names.

Nice. And by "nice" I mean halle-fuckin-lujah!

I should give some credit for this tip. I originally read about it here at MacGeekery, but didn't quite understand it until I read some posts on various forums. Of course, there's nothing like a real-world problem to solve, and I had this as well to aid my understanding of this method.