Renaming with Larry Wall

When Eddie Smith of Practically Efficient tweeted this the other day,

I don’t use it often, but when I do it saves me so much time: A Better Finder Rename…

8:15 PM Tue Sep 13, 2011

I followed the link to A Better Finder Rename (known as just Better Rename in the Mac App Store, for reasons that aren’t clear to me), an application I’d heard about but had never really looked into.

I downloaded the trial version and played around with it for a while. It’s impressive. There are lots of options, but they seem to be laid out in a way that’s easy to keep track of and use.

A Better Finder Rename

Will I buy it? Dunno. That Eddie uses it is a strong testimonial, but I have a couple of file renaming scripts that I’ve been using for years.

The first is canonize, which renames photo files according to the date and time they were taken by reading their EXIF data. Since I presented its source code in an earlier post, I won’t repeat myself here.

The other is a very old Perl script, the guts of which was taken from a script Larry Wall presented in the first edition of Programming perl. I call it rename:

 1:  #!/usr/bin/perl
 3:  use Getopt::Std;
 5:  $usage = <<USAGE;
 6:  rename - renames files via a Perl expression. Adapted from Larry Wall's
 7:           program in the first (pink) edition of the Camel book.
 9:  usage: rename [options] '<perl expr>' files
10:  options:
11:      -t:   test - show how the renaming would be done, but don't do it
12:      -h:   help - print this message
14:  The Perl expression is mandatory. A variable, $n, can be used in the Perl
15:  expression to insert a sequence number into the new name. The files can
16:  be listed on the command line, piped in through STDIN, or given in a file,
17:  one per line.
18:  USAGE
20:  # Process options.
21:  getopts('th', \%opt);
22:  die $usage if ($opt{h});
24:  # Make sure there's a perl expression.
25:  ($perlexpr = shift) || die $usage;
27:  # Handle the different ways of getting the file names.
28:  chomp(@ARGV = <STDIN>) unless @ARGV;
30:  # Set up a one-based file counting variable.
31:  $n = 1;
33:  # Do the renaming or show how it would be done.
34:  foreach (@ARGV) {
35:    $old = $_;
36:    eval $perlexpr;
37:    die $@ if $@;
38:    if ($opt{t}) {
39:      print "$old => $_\n";
40:    }
41:    else {
42:      rename($old, $_) unless $old eq $_;
43:    }
44:    $n++;
45:  }

Like A Better Finder Rename, and unlike Wall’s original script, rename can show you what the renaming will be before you actually do it. It takes advantage of Perl’s regular expression engine to do almost any renaming you can imagine. I was able to mimic the ABFR example above with this command

rename -t 's/^[^.]+\./sprintf("fred-%03d.", $n)/e' *.txt  

The results were what you’d expect:

a.txt => fred-001.txt
b.txt => fred-002.txt
c.txt => fred-003.txt
d.txt => fred-004.txt

Running the same command without the -t option would go ahead and do the renaming. The trick here is to use the $n variable provided by rename and use Perl’s /e flag on the substitution command to be able to put executable code within the replacement string. In the source code, the sequence number, $n, and the -h and -t options were my idea; the rest is basically Wall’s original.

If I didn’t feel comfortable with regular expressions, I wouldn’t hesitate to buy ABFR—it provides much more hand-holding. But I admit I like the feeling of wizardry that comes from using rename.