Bash: Working with filenames containing spaces

Here’s a quick tip for part time bash hackers like me. Let’s say you want to iterate over all mp3’s in a directory and add a prefix string (the album name) to each filename. The only problem is that the fool who created these files has added spaces in the filenames (shock, horror, gasp).

Your first reaction may to be write something like below.

for FILENAME in $(ls *.mp3); do
  mv -v "${FILENAME}" "${PREFIX} - ${FILENAME}"

On the face of it this looks like it should work but it doesn’t. Bash will iterate tokens split not only by filename but also by the spaces in each filename so you will get far more tokens than you expected and the move operation will go horribly wrong.

In fact the correct answer, upon investigation, emerges to be as below.

find . -name '*.mp3' | while read FILENAME; do
  mv -v "${FILENAME}" "${PREFIX} - ${FILENAME#./}"; 

Note the use of parameter expansion in the destination filename: ${I#./}. This is necessary because by default the $FILENAME variable begins with ./ to say that it lives in the current directory so that code simply removes the smallest match of ./ from the beginning of the string. This was tested on OS X Lion only. Done.

Incidentally – this script was actually being used to prefix mp3 files (with album names) that belong to a new band I’ve just come across called LDUK. Check them out if you haven’t heard of them. They’re very good – twitter, facebook, youtube. My favourite tracks are Room of Anger Jungle and Artistic Vortex. You can also download three free full albums here.

3 thoughts on “Bash: Working with filenames containing spaces

Leave a Reply