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 に答える