使用Perl重命名目录中的文件
我想获取一个目录,对于所有电子邮件(*.msg)文件,请删除开头的“RE”。我有以下代码,但重命名失败使用Perl重命名目录中的文件,perl,file,directory,rename,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
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";
}
如果您的
/emails
目录包含以下文件:
1.msg
2.msg
3.msg
然后,您的@文件
将看起来像('.','..,'1.msg',2.msg',3.msg')
,但是您的重命名
需要像'emails/1.msg'
,'emails/2.msg'
这样的名称。因此,在重命名之前,您可以:
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
您可能希望使用以下方法将目录读取和筛选结合起来:
甚至这个:
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);
你似乎是在假装,而不是假装
底层的readdir
系统调用只返回目录中的文件名,并将包括两个条目
和。
。这将贯穿到Perl中的readdir
函数,只是为了更详细地介绍mu的答案
或者,如果您正在以某种方式收集数组中的所有结果,那么使用readdir
也没有多大意义
@files = glob('emails/*');
如前所述,脚本失败是因为预期的路径和脚本使用的路径不同 我建议使用更透明的方法。在我看来,硬编码目录不是一个好主意。有一天,我编写了一个脚本,用硬编码的路径修改一些原始文件,我的一位同事认为这是一个很好的脚本,可以借来修改他的副本。哎呀 用法:
perl script.pl "^RE " *.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 $!;
}
}
i、 e.regex,然后是一个文件全局列表,其中的路径表示与脚本相关,例如*.msg
,emails/*.msg
甚至/home/pat/emails/*.msg/home/foo/*.msg
。(可能有多个全局)
使用绝对路径将让用户毫无疑问地知道他将影响哪些文件,并且还将使脚本可重用
代码:
perl script.pl "^RE " *.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 $!;
}
}
我不知道正则表达式是否适合文件的指定名称,但在一行中,这可以通过以下方法完成:
perl-E'for(){($new=$)=~s/(^RE)(.*$)/$2/;比如说$.->“$new}
(say…
很适合测试,只需将其替换为rename$\u$new
或rename($\u$new)
)
读取当前目录中的每个文件($new=$\u)=~
将以下替换保存在$new
中,并保持$\ucode>不变
(^RE)
将此匹配项保存在$1(可选)中,只需在开始处将文件与“RE”匹配即可(.*$)
将所有内容保存到并包括行的结尾($)->到$2中$2
如果您打印错误($!),您可能会了解出了什么问题……感谢您指出这一点。错误是“没有这样的文件或目录”。我很惊讶,$old文件名是准确的。请注意,
rename
不提供跨平台支持,而file::Copy
的move
功能does@Zaid:但它是否也保留权限,跨平台?非常好。感谢您解释这一点。+1提醒我存在glob
。glob
的缺点是,由于'emails/'
前缀的存在,它会使名称有点混乱,这是一个很小的问题,但处理起来很简单。嗨,我真的很喜欢这个想法。我的$new=s/$rx//r行似乎有错误。输出是“在运算符应位于“s/$rx//r”附近的位置找到的裸字,并且在same@JP. 哦,那可能是因为你的perl版本。。你使用哪个版本?@JPcorelist“/r”
为我提供了/r是与perl v5.8.9一起发布的,因此早期版本中没有非破坏性选项。@JP。那就行了。代码对我有用。您是否使用“^RE”
作为正则表达式?正则表达式中不应该有斜杠。要么是这样,要么是复制/粘贴到您的终端时出错。您可以检查以确保您可以在您的版本中使用/r
和say
。@JP。如果是/r
选项,则很容易解决。只需将该行替换为my$new=$\$新=~s/$rx/代码>。