我的Perl脚本应该打开目录中的所有文件,并在其中搜索模式,然后打印包含模式的整行。下面是代码。该代码无法打开文件。
my $dir = 'dir1/dir2';
opendir (DIR, $dir) or die $!;
my @dir = readdir DIR;
foreach my $item (@dir) {
open(FILE, "<", "file.txt")
or die "Can't open < file.txt: $!";
while($line= <FILE>) {
print "$line" if $line=~ /pattern/;
}
close FILE;
}
closedir DIR;
请提出一些可行的方法。
该readdir的回报只是名称(file.txt
),而不是路径(不dir1/dir2/path.txt
)。
因此,当程序尝试打开$item
†时,结果表明没有这种东西需要打开"$dir/$item"
。或者,将其放在文件列表中的每个条目之前,然后使用正确的路径
use warnings;
use strict;
my $dir = 'dir1/dir2';
opendir (my $dh, $dir) or die $!;
my @entries = map { "$dir/$_" } readdir $dh;
closedir $dh;
foreach my $item (@entries) {
next if not -f $item;
open(my $fh, "<", $item) or die "Can't open < $item: $!";
while(my $line = <$fh>) {
print $line if $line =~ /pattern/;
}
close $fh;
}
请注意,我跳过了不是常规文件的条目(not -f
请参阅filetest运算符),并使用词法文件句柄代替typeglobs(my $fh
代替FILE
)。
获取条目列表的另一个选项是glob(请参阅File :: Glob),它确实返回路径:
my @entries = glob $dir; # dir1/dir2/file.txt (etc)
但是,如果确实要提前获取整个文件列表,而不是一次读取和处理一个项目,那么您最好立即根据需要对其进行过滤,因此
my @files = grep { -f } glob $dir;
现在您只有常规文件。
当然,也可以在上面的程序中过滤整个列表。map
本身就能做到
opendir (my $dh, $dir) or die $!;
my @files = map { -f "$dir/$_" ? "$dir/$_" : () } readdir $dh;
closedir $dh;
这里map
也有一些过滤器的作用:一个空列表()
(当条目不是纯文件时返回)在返回列表中变平从而有效消失,因此在这种情况下等于不返回任何内容。或者,连锁grep
到map
像往常一样
my @files = grep { -f } map { "$dir/$_" } readdir $dh;
这的确使列表再次获得通过,但这是经过优化的,几乎不需要担心(除非我们有巨大的文件列表-它本身就带来了问题-并且经常这样做)。
我还想提到,为此也有很好的模块。
Path :: Tiny的示例
use Path::Tiny;
my $it = path($dir)->iterator;
while (my $entry = $it->()) {
# it omits . and ..
}
这是一个“惰性”迭代器。有关此模块提供的许多其他功能,请参见文档,以及更多信息。
†而不是file.txt
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句