1
    my $directory = shift @_;
    my @dh;
    my @files;

    opendir (my $dh, $directory) or die "Couldn't open dir '$directory' : $!";
    foreach my $file(readdir $dh) {
        if( -f $file =~ /\.htm$/){
                    push(@files,$file);
        }
        elsif(-d $file){
            push(@dh,$file);
            $dh = shift @dh;
        }

        closedir ($dh);
    }

我试图让我的脚本采用路径,例如 DATA/ (这是成功的),但是我希望我的脚本扫描该目录和子目录,然后如果有任何文件匹配,它将存储在@files.

我正在尝试使用循环扫描所有子文件夹,例如

elsif(-d $file){
    push(@dh,$file);
    $dh = shift @dh;
}

在这个语句中$dh会得到一个新的子目录名来扫描

但是我得到Segmentation fault

4

1 回答 1

3

这里有几个问题:

  • readdir返回伪目录...这些应该被忽略

  • readdir只返回文件名而不是文件的完整路径。因此-f,并且-d将在当前工作目录中查找具有此名称的条目,并且可能找不到它

  • 您正在将目录名称推送到@dh但将目录句柄$dh移出它,这是行不通的

  • 测试-f $file =~ /\.htm$/首先将正则表达式应用于$file变量,然后将结果(或1"")用作 的参数-f。这根本不是你想要的

  • 你一找到一个新目录就跳到处理一个新目录,所以当前目录的其余部分不会被处理

像这样的事情通常使用File::Find递归子程序来完成,但是您可以通过消除尾递归来完成类似的事情。请注意,它不考虑目录链接,如果找到一个,它可以无限循环。这就是为什么最好使用解决所有这些问题的模块的原因。

use strict;
use warnings;

my @dh = @_;
my @files;

while (@dh) {

  my $directory = shift @dh;
  opendir my $dh, $directory or die "Couldn't open dir '$directory' : $!";

  while (readdir $dh) {
    next if /\A\.\.?\z/;
    my $node= "$directory/$_";

    if (-f $node and /\.html?$/i) {
      push @files, $node;
    }
    elsif (-d $node) {
      push @dh, $node;
    }
  }

}
于 2013-05-04T04:54:33.790 回答