使用Perl重命名目录中的文件

时间:2011-12-09 19:40:33

标签: perl file directory rename

我想要一个目录和所有电子邮件(* .msg)文件,删除开头的'RE'。我有以下代码但重命名失败。

opendir(DIR, 'emails') or die "Cannot open directory";
@files = readdir(DIR);
closedir(DIR);

for (@files){
    next if $_ !~ m/^RE .+msg$/;
    $old = $_;
    s/RE //;
    rename($old, $_) or print "Error renaming: $old\n";
}

4 个答案:

答案 0 :(得分:9)

如果您的./emails目录包含以下文件:

1.msg
2.msg
3.msg

然后您的@files看起来像('.', '..', '1.msg', '2.msg', '3.msg'),但您的rename想要'emails/1.msg''emails/2.msg'等名称。所以你可以{{3}重命名之前:

chdir('emails');
for (@files) {
    #...
}

您可能也想查看chdir返回值。

或者自己添加目录名称:

rename('emails/' . $old, 'emails/' . $_) or print "Error renaming $old: $!\n";
# or rename("emails/$old", "emails/$_") if you like string interpolation
# or you could use map if you like map

您可能希望使用chdir组合目录读取和过滤:

my @files = grep { /^RE .+msg$/ } readdir(DIR);

甚至是这样:

opendir(DIR, 'emails') or die "Cannot open directory";
for (grep { /^RE .+msg$/ } readdir(DIR)) {
    (my $new = $_) =~ s/^RE //;
    rename("emails/$_", "emails/$new") or print "Error renaming $_ to $new: $!\n";
}
closedir(DIR);

答案 1 :(得分:5)

您似乎假设glob - 就像行为而不是readdir一样行为。

基础readdir系统调用仅返回目录中的文件名,并包含两个条目...。这继续到Perl中的readdir函数,只是为了更详细地介绍一下mu的答案。

或者,如果您正在收集数组中的所有结果,那么使用readdir并没有多大意义。

@files = glob('emails/*');

答案 2 :(得分:2)

如前所述,由于您期望的路径和脚本使用的路径不同,您的脚本会失败。

我建议使用更透明的用法。对目录进行硬编码不是一个好主意,IMO。正如我在有一天学到的那样,我制作了一个脚本来改变一些原始文件,用硬编码的路径,我的同事认为这将是一个很好的脚本借用来改变他的副本。哎呀!

<强>用法:

perl script.pl "^RE " *.msg

即。正则表达式,然后是文件全局列表,其中路径相对于脚本表示,例如, *.msgemails/*.msg甚至/home/pat/emails/*.msg /home/foo/*.msg。 (多个可能的球)

使用绝对路径将使用户毫不怀疑他将影响哪些文件,并且还将使脚本可重用。

<强>代码:

use strict;
use warnings;
use v5.10;
use File::Copy qw(move);

my $rx = shift;   # e.g. "^RE "

if ($ENV{OS} =~ /^Windows/) {  # Patch for Windows' lack of shell globbing
    @ARGV = map glob, @ARGV;
}

for (@ARGV) {
    if (/$rx/) {
        my $new = s/$rx//r;  # Using non-destructive substitution
        say "Moving $_ to $new ...";
        move($_, $new) or die $!;
    }
}

答案 3 :(得分:0)

我不知道正则表达式是否适合文件的指定名称,但是可以用以下一行完成:

perl -E'for (</path/to/emails*.*>){ ($new = $_) =~ s/(^RE)(.*$)/$2/; say $_." -> ".$new}

({say ...非常适合测试,只需将其替换为rename $_,$newrename($_,$new)

  1. <*.*>读取当前目录中的每个文件
  2. ($new = $_) =~将以下替换保存在$new中,并使$_保持不变
  3. (^RE)将此匹配项保存在$ 1(可选)中,只匹配开头为“ RE”的文件
  4. (.*$)保存直到-包括行末($)在内的所有内容到$ 2
  5. 将匹配项替换为$2中的字符串