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 publicspace.net/ABetterFinderR…

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
 2:  
 3:  use Getopt::Std;
 4:  
 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.
 8:  
 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
13:  
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
19:  
20:  # Process options.
21:  getopts('th', \%opt);
22:  die $usage if ($opt{h});
23:  
24:  # Make sure there's a perl expression.
25:  ($perlexpr = shift) || die $usage;
26:  
27:  # Handle the different ways of getting the file names.
28:  chomp(@ARGV = <STDIN>) unless @ARGV;
29:  
30:  # Set up a one-based file counting variable.
31:  $n = 1;
32:  
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.


5 Responses to “Renaming with Larry Wall”

  1. Jan says:

    I just use an really simple and small Automator Service for renaming files.

    Very handy and free.

  2. Lri says:

    A similar utility comes pre-installed in many environments. But on OS X you could brew install rename.

    There are also versions for other languages, like http://technetra.com/2008/11/11/codemagic-renamerb-a-ruby-version-of-perls-rename-command.

    I had to write my own script too: runame - a nooby Ruby batch rename script — Gist. Its idiomaticness is comparable to the mathematical rigor of that infinite series proof though.

    $ runame 'gsub f,"fred-""%03d"%n+x' *
    a.txt -> fred-001.txt
    b.txt -> fred-002.txt
    c.txt -> fred-003.txt
    d.txt -> fred-004.txt
    Continue?
    
  3. Dr. Drang says:

    Jan,
    I can see the advantage of an Automator script if you don’t have Terminal open all the time, but my experience with Automator has always been frustrating because it seems to take forever to get going. Has that been improved lately?

    Lri,
    I remember there being a /usr/bin/rename in every Linux distribution I used, but I always preferred my variant of Wall’s because I had no question of how it worked.

    I don’t know whether it’s a defect in my brain or just a lack of exposure, but Ruby always looks really weird to me. But I can read it well enough to know that I should steal your “Continue?” part to add to my -t option. Much better to just go ahead with the renaming if the test looks good than to rerun the command without the -t.

  4. Clark says:

    known as just Better Rename in the Mac App Store, for reasons that aren’t clear to me

    If I recall there’s a rule about Apple’s application names to avoid confusion.

    I own Better Finder Rename since it came with a bundle I got a while back. I have to say I’ve only used it twice. I’m like you - I typically have a few scripts written to modify files and it’s just easier to modify that.

  5. Randal L. Schwartz says:

    You didn’t need $n. You could’ve just used “$.” which would have been sequentially higher for each processed record.