Приглашаем посетить
Булгарин (bulgarin.lit-info.ru)

Section 12.8.  Renaming Files

Previous
Table of Contents
Next

12.8. Renaming Files

Giving an existing file a new name is simple with the rename function:

    rename "old", "new";

This is similar to the Unix mv command, taking a file named old and giving it the name new in the same directory. You can even move things around:

    rename "over_there/some/place/some_file", "some_file";

This moves a file called some_file from another directory into the current directory, provided the user running the program has the appropriate permissions.[Section 12.8.  Renaming Files] Like most functions that request something of the operating system, rename returns false if it fails, and sets $! with the operating system error, so you can (and often should) use or die (or or warn) to report this to the user.

[Section 12.8.  Renaming Files] And the files must reside on the same filesystem. You'll see why this rule exists a little later in this chapter.

One frequent[*] question in the Unix shell-usage newsgroups is how to rename everything that ends with .old to the same name with .new. Here's how to do it in Perl:

[*] This isn't just any old frequent question; the question of renaming a batch of files at once is the most frequent question asked in these newsgroups. And that's why it's the first question answered in the FAQs for those newsgroups. And yet, it stays in first place. Hmmm.

    foreach my $file (glob "*.old") {
      my $newfile = $file;
      $newfile =~ s/\.old$/.new/;
      if (-e $newfile) {
        warn "can't rename $file to $newfile: $newfile exists\n";
      } elsif (rename $file, $newfile) {
        ## success, do nothing
      } else {
        warn "rename $file to $newfile failed: $!\n";
      }
    }

The check for the existence of $newfile is needed because rename will rename a file right over the top of an existing file, presuming the user has permission to remove the destination filename. We put the check in so that it's less likely that we'll lose information this way. If you wanted to replace existing files, like wilma.new, you wouldn't bother testing with -e first.

Those first two lines inside the loop can be combined (and often are):

    (my $newfile = $file) =~ s/\.old$/.new/;

This works to declare $newfile, copy its initial value from $file, and modify $newfile with the substitution. You can read this as "transform $file to $newfile using this replacement on the right." And yes, because of precedence, those parentheses are required.

Some programmers seeing this substitution for the first time wonder why the backslash is needed on the left but not on the right. The two sides aren't symmetrical: the left part of a substitution is a regular expression, and the right part is a double-quoted string. So we use the pattern /\.old$/ to mean ".old anchored at the end of the string" (anchored at the end because we don't want to rename the first occurrance of .old in a file called betty.old.old), but on the right we can write .new to make the replacement.

    Previous
    Table of Contents
    Next