August 7, 2009

Working with filenames containing spaces in Bash

The problem: spaces in filenames

Sometimes you’ll need to manipulate a list of filenames which contain spaces using a for’ loop. Let’s say you have the following two files:

Command:

$ ls -1

Output:

Aisling, Sanda and Justin.jpg
Monika, Sanda, Justin, Michelle and Ben.jpg

They list perfectly well - one file on each line. (I used the -1’ [minus one] option to ls’ to make a single-column list)

However something strange happens when you want to reference them individually for a for’ loop. Here I use a for’ loop to see how the filenames are being passed to the echo’ command:

Command:

$ for line in $(ls -1) ; do echo ${line} ; done

Output:

Aisling,
Sanda
and
Justin.jpg
Monika,
Sanda,
Justin,
Michelle
and
Ben.jpg

Aaagh! The filenames are being chopped up at the spaces and at the newlines!

The solution: a custom value for $IFS

I need to be able to tell bash that I only want it to chop up lists at the newline character. For this, I modify the value of the built-in variable, IFS. The name stands for Internal Field Separator’.

IFS normally has the value - that’s to say, space, tab and newline. Let’s reset it so that it only contains the newline character:

$ IFS=$‘’

See how I specify the newline character? That’s important. It’s different from how you’d normally set a shell variable. I don’t want the literal string ’, I want what that string represents - a newline.

Now I run the same for’ loop again:

Command:

$ for line in $(ls -1) ; do echo ${line} ; done

Output:

Aisling, Sanda and Justin.jpg
Monika, Sanda, Justin, Michelle and Ben.jpg


Now I can manipulate the filenames as I originally intended.

An example: get rid of those spaces!

Here’s a shell script that uses the tr’ command to rename a list of files, replacing tab and space characters in filenames with underscores:

#!/bin/bash

# Back up the current value of IFS
IFS=$IFS

IFS=$‘’

for line in $(ls -1) ; do
   newname=$(echo ${line} | tr ’ ’ ’
’)
   escapedname=$(echo ${line} | tr ’ ’ “ ”)
   mv ${escapedname} ${newname}
done

# Restore IFS
IFS=$_IFS

Here’s what my files look like after I’ve run that script:

Aisling,_Sanda_and_Justin.jpg
Monika,_Sanda,_Justin,_Michelle_and_Ben.jpg




Previous post
Using Oracle Import and Export This is a description on how to use Oracle’s and utilities to move tables between databases. It transfers the data over the network, which avoids
Next post
“…like watching paint dry” Colleagues who volunteer comments like “testing is more boring than watching paint dry!” make me laugh. To me that displays an astonishing lack of