Max79 has asked for the wisdom of the Perl Monks concerning the following question:

Dear all My name is Max, I am just a beginner in the world of Perl and so I apologize if my question, that seems to me so hard that I can get through by myself, is indeed silly. I got a dir plenty of files like that:

GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_103721.jpg GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_103721.xml

The number of this files are not sequential I would like to rename this file in a more handy way as 1.jpg and 1.xml, 2.jpg 2.xml up to the last one. In the position number 498 and 500 of the file *xml there are two numbers. I would like also to create a directory with this two numbers (something as 15 or 20) and move in this directory the corresponding files. So if th20120315_103721.xml has in position 498 and 500 the numbers 1 and 5 I would like to move this file and corresponding jpeg in the dir 15 and so on. I started step by step. First with a script that should have modified the name but indeed remove the files !

< #!/usr/bin/perl -w ## ## use strict ; my $dir = 'ParticleAcquisitionDataImages/'; my @fileList = glob "${dir}*jmg*"; foreach (@fileList) { next if -d; my $oldname = $_; # $_=substr($_, 0, 1, ''); # s/.//; s/^.(.*).$/$1/; rename $oldname, $_ or $_ = $oldname, warn $_, ' not renamed: ', $!; } close >
Thank you in advance Max

Replies are listed 'Best First'.
Re: Renaming files in a directory in sequence
by Anonymous Monk on Mar 28, 2012 at 21:16 UTC

    My advice is do not attempt renaming but first generate a list of moves and then review that list

    See similar questions Changing filenames, Multiple File Rename

    So, I would start with a program like

    #!/usr/bin/perl -- use strict; use warnings; use Data::Dump qw/ dd pp /; use File::Basename qw/ fileparse /; use File::Copy qw/ move /; # RENAME Main( @ARGV ); exit( 0 ); sub Main { my @files = qw' err/error.txt GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_103 +721.jpg GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_103 +721.xml blah_foo.jpg blah_bar.xml blah/foo.jpg blah/bar.xml '; my @rename = makeRenameList( @files ); fakeRename( @rename ); } sub fakeRename { print "\n"; for my $name ( @_ ){ print "rename ", pp( $name ), "\n\n"; } } sub makeRenameList { my @fromTo; my %rename_index = ( qw/ .jpg 1 .xml 1 / ); LOOP_FROMFILE: for my $fromFile ( @_ ){ my($directory, $filename, $suffix) = $fromFile =~ m{^(.*?)(?: +([^/]*?)(\.[^\.]*))?$}; if( not exists $rename_index{lc $suffix} ){ warn "Unknown suffix ($suffix) ignoring($fromFile)"; next LOOP_FROMFILE; } my $toFile = join '', $directory, $rename_index{lc $suffix}++, $suffix; push @fromTo, [ $fromFile, $toFile ]; } return @fromTo; } __END__

    Which would print

    Unknown suffix (.txt) ignoring(err/error.txt) at - line 41. rename [ "GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_ +103721.jpg", "1.jpg", ] rename [ "GridSquare_0000000077_FoilHole_0000000001_Data_0000000002_20120315_ +103721.xml", "1.xml", ] rename ["blah_foo.jpg", "2.jpg"] rename ["blah_bar.xml", "2.xml"] rename ["blah/foo.jpg", "blah/3.jpg"] rename ["blah/bar.xml", "blah/3.xml"]

    Next I might change sub makeRenameList to

    and so on and so forth, until I'm satisfied with output of fakeRename, than I might call realRename :)

Re: Renaming files in a directory in sequence
by graff (Chancellor) on Mar 29, 2012 at 05:47 UTC
    Your code really makes no sense relative to your example file names and your stated goals. Also, I don't see how the OP code would remove files -- more likely it would just generate a lot of error messages and warnings.

    I agree with the previous reply: your script should just print out a list of "oldname newname" pairs (one pair per line). Once you confirm that the names are coming out right, just include "mv" (or "rename", depending on your OS) at the start of each line, and you can use the list as a shell script to actually change the file names.

    For that matter, it might be easier for you to create the list of original file names as a list that your script can read as input, instead of using 'glob' in the script. That way, if you still have trouble getting it to do what you want. you can post a few lines from the input list, along with the script that tries to work on that input, so we'll have a better idea of the problem.

Re: Renaming files in a directory in sequence
by thundergnat (Deacon) on Mar 28, 2012 at 14:15 UTC

    It is not clear if the files should be renamed sequentially then moved to the new directory, or if the files should be moved then renamed.

    Anyway, here is one way you might do the former... if you need the latter this can easily be adapted. This looks for all the .jpg files in the specified directory then only proceeds if there is a corresponding .xml file. The sort on @files is not strictly necessary and could be removed; glob() returns file names in OS sorting order. If you need some other order though, that is a good place to specify it.

    Note: As this is written, if there are files already in one of the destination directories with the same name as the renamed jpeg/xml files, they will be clobbered.

    use warnings; use strict; use File::Basename; use File::Copy; my $dir = 'ParticleAcquisitionDataImages/'; # or whatever my @files = glob "${dir}*.jpg"; my $rename_index = 1; for my $file ( sort @files ){ next if -d $file; my($filename, $directory, $suffix) = fileparse($file, '.jpg'); next unless -e "${dir}$filename.xml"; $filename = changename($filename); open my $fh, '<', "${dir}$filename.xml" or die "$!"; seek($fh, 498, 0); my $newdir; read($fh, $newdir, 3); close $fh; substr $newdir, 1, 1, ''; mkdir "$dir$newdir" unless -e "$dir$newdir"; for my $ext ( qw/.jpg .xml/) { move "$dir$filename$ext", "$dir$newdir/$filename$ext" or die $ +!; } } sub changename { my $filename = shift; for my $suffix ( qw/.jpg .xml/) { rename "$dir$filename$suffix", "$dir$rename_index$suffix" or d +ie $!; } return $rename_index++; }
      Thank you so much to everybody for the help.