How-to: Loop over filenames with spaces in Bash

Today I needed to rename 92 photo files I exported out of Adobe Lightroom. I didn't want to re-export them since it would take a few minutes with my project sitting on a slow SD card and I didn't want to manually rename each of them in the Apple Finder. So instead I opted to write a quick-and-dirty Bash script to automate the task for me.

#!/bin/bash
  
OIFS="$IFS"
IFS=$'\n'
for file in `find . -type f -name "*.jpg"`
do
        file_number="$(echo "$file" | sed 's/.* - \(.*\.jpg\)/\1/')"
        mv "$file" "convoy-of-hope-$file_number"
done
IFS="$OIFS"

The tricky part of this script was handling the filenames of my photos because they had spaces in them, which doesn't play well with the mechanics of the Bash for loop:

for file in `find . -type f -name "*.jpg"`

For a file named My photo file name.jpg, this Bash for loop would loop four times with "My", "photo", "file", and "name.jpg". This is because the for loop uses spaces as the default field separator in each loop.

# This is not what I want
for file in "My" "photo" "file" "name.jpg"

# This is what I want
for file in "My photo file name.jpg"

Therefore, I needed to change the field separator to tell Bash to only split the list of filenames after encountering a newline:

IFS=$'\n'

Thank You God for programming automation!

Explore More