A quickie today, renaming a bunch of files in the shell. Unix gives you million ways to do it, here are a few that will help you understand your tools better.

The word has come down, Uber is the new Awesome and our files must reflect this (management is behind the curve, but they pay the bills).

Bash

With Bash we can take advantage of it’s Substring Replacement. The format is ${variable/old_string/new_string} and does what you’d image.

1
2
3
4
for f in *awesome*
do
    mv $f ${f/awesome/uber}
done

tcsh

Personally, I find tcsh’s foreach loop format cleaner:

1
2
3
foreach f ( *awesome* )
  mv $f `echo $f | sed s/awesome/uber/`
end

However tcsh doesn’t have variable substitution, so we end up invoking sed to get the new name. Backticks are key here, echoing the filename into sed causing it to output the name with the substitution. The backticks capture that output and make it an argument to mv.

find | xargs

Then there’s find and xargs:

1
find . -name '*awesome*' | sed 'p;s/awesome/uber/' | xargs -n2 mv

This as the advantage of searching through subdirectories. find prints all file (or directories) containing the awesome in the name. sed has two commands p which just prints the original file name and then the s substitution. We end up with a list that looks like:

1
2
3
4
./one_awesome.c
./one_uber.c
./two_awesome_door.txt
./two_uber_door.txt

The -n2 option to xargs says “process the input two entries at a time” and mv is the command to apply to those entries. In effect this generates:

1
2
mv ./one_awesome.c ./one_uber.c
mv ./two_awesome_door.txt ./two_uber_door.txt

find can also be used in the for loops to handle files in subdirectories.

1
for f in `find . -name '*awesome*'`
1
foreach f ( `find . -name '*awesome*'` )

The backticks captures find’s output and inserts it as the files list for the loop.

rename

Last, possibly easiest, and most confusing is rename. Rename is a problem because there are two different things called rename. One, typically found RHEL type systems takes three arguments, the original string, the new string and the filenames:

1
rename awesome uber *awesome*

Then there is the other, typically found on Debian/Ubuntu which takes a Perl expression.

1
rename s/awesome/uber/ *awesome*

If you do have rename and you know which rename you have, it doesn’t get much simpler. The Mac doesn’t ship with either, though it’s easy enough to install one.

One problem, four approaches. More importantly, a bunch of techniques that you can reach for when you need to manipulate a collection of files.

Comments