[pm-h] substitution with increment

G. Wade Johnson gwadej at anomaly.org
Mon Aug 20 04:59:39 PDT 2007


On Mon, 20 Aug 2007 01:50:18 -0500
"Russell L. Harris" <rlharris at oplink.net> wrote:

> I have several dozen groups of files; each group consists of one to
> several hundred files.  
> 
> Within each group, the bash "ls" command lists the files in proper
> order, because the filename includes a multi-character identifier
> (such as 43-29, 43-30, 44-01, 44-02, etc.).
> 
> I need to add to the file names within each group a file number, such
> that the files may be referenced in proper order as 001, 002, 003,
> etc.  It is important that the file number contain exactly three
> digits.

Constructing the file names looks like a job for sprintf.

> I am making other changes to the filename, and I have been able to
> accomplish everything (undoubtedly crudely) with the diamond operator
> and the substitution operator s/// (using the "g" suffix).  But I have
> not figured out a reasonable scheme for adding the sequential file
> number.  Can this be done with s/// ?

There's a great piece of code in the Perl Cookbook that works as a very
powerful rename command. It takes the old filename, applies some Perl
code to it, and then renames the file (if the old and new names are
different).

I would actually do this part separately from any other processing.
Loop over the list of filenames, creating the new name from a counter.
Use the rename() function to do the actual file renaming. One case
where I have used it is renaming files from a digital camera.

My camera generates files of the form DSCN0123.JPG. Let's say I wanted
to rename a large set of them to have a more useful name, I would use
the loop below.

my $counter = 1;
foreach $file (@ARGV)
{
    my $newname = sprintf( 'Vacation2007-%04d.jpg', $counter );
    if(!rename( $file, $newname ))
    {
        warn "Failed to rename $file to $newname\n";
    }
}

You can also extract information from the old file name to use when
constructing the new name. For example, say I just wanted to keep the
old filenames, but change them from 4 digits at the end to five.

foreach $file (@ARGV)
{
    my $newname = $file;
    $newname =~ s/DSCN(\d+).JPG/DSCN0$1.JPG/;
    if(!rename( $file, $newname ))
    {
        warn "Failed to rename $file to $newname\n";
    }
}

Hope that helps.
G. Wade
-- 
You forgot the first rule of the fanatic: when you become obsessed with
the enemy, you become the enemy.      -- Jeffrey Sinclair in "Infection"


More information about the Houston mailing list