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

I have a directory with file names like: 2, 5, 7.

I have a file in sorted order containing names that corresponds to each file name. The the first line in the file would be the name of 2, the second would be 5, and so on.

What I want to do is rename each file to the name it corresponds to in the file. Example:

  • 2 rename to testfile1
  • 5 rename to testfile2
  • 7 rename to testfile3
  • I'm unsure how to approach doing this. Do I want to to create an array of the file names, sort it numerically and then go about renaming them? How would I make sure that the file named '2' corresponds to right line in the file I have of names?

    Replies are listed 'Best First'.
    Re: rename files
    by RoyCrowder (Monk) on Apr 08, 2009 at 15:22 UTC
      You could do something like this.
      opendir(DIR, $some_dir) || die "can't opendir $some_dir: $!"; my @files = grep { /^\./ && -f "$some_dir/$_" } readdir(DIR); closedir(DIR); @files = sort {$a <=> $b} @files; # Ascending sort my $count = 1; foreach (@files) { rename($_, "testfile$count") or warn "rename: $_ : $!"; $count = $count + 1; }
      You don't have to use a separate file of sorted file names. You can use the code above or a variation there of to get the job done. In reading your post I saw you wanted the files not to correspond to their number (ie: 2 != testfile2, 2 == testfile1). This can be done by keeping an incremental count. If you want to keep the separate file of sorted filenames just ignore the first part.
    Re: rename files
    by repellent (Priest) on Apr 08, 2009 at 18:00 UTC
      Are you on a Unix platform? How about, first:
      > perl -ne ' BEGIN { $i = 0 }; next if /^\s*$/; s/^/mv /; s/$/" testfile" . ++$i/e; print' filenames.txt > renames.sh

      Then look through renames.sh and make sure you're happy with it. Then on the command line:
      > sh renames.sh
    Re: rename files
    by cdarke (Prior) on Apr 08, 2009 at 14:16 UTC
      open(my $fh, $namefile) or die "$namefile: $!"; while (<$fh>) { rename ($_, "testfile$_") or warn "rname $_: $!"; } close($fh);
      (Untested)

        You probably want a chomp at the top of the loop?

        G. Wade
        You provided this code:
        open(my $fh, $namefile) or die "$namefile: $!"; while (<$fh>) { rename ($_, "testfile$_") or warn "rname $_: $!"; } close($fh);

        This does not meet the spec given, even if you chomp the lines. Even if the data file was changed to contain the current names of the files, it wouldn't meet the spec given. The names of the files pbaumgar has and the names desired cannot be reconciled by concatenation alone.

        RoyCrowder's solution achieves the desired effect if the data file all follows from the example. Otherwise, keeping the file of new filenames as in the spec would be more desirable, like this minor modification to RoyCrowder's existing code:

        opendir(DIR, $some_dir) || die "can't opendir $some_dir: $!"; my @files = grep { /^\./ && -f "$some_dir/$_" } readdir(DIR); closedir(DIR); @files = sort {$a <=> $b} @files; # Ascending sort open my $names, '<', 'newnames.txt' or die "Cannot read newnames.txt: +$!\n"; foreach (@files) { my $name = <$names>; chomp $name; rename($_, $name) or warn "rename: $_ : $!"; }

          Your solution does meet the spec, but it's really just a disaster waiting to happen. Keeping the directory contents and the names file in sync will be a challenge and really seems unmaintainable.

          I'd really be interested in what pbaumgar is actually trying to solve here.