4

私はPerlのFile::Findモジュールを見て、次の方法で試しました。

#!/usr/bin/perl

use warnings;
use strict;

use File::Find;

find({wanted => \&listfiles,
        no_chdir => 1}, ".");


sub listfiles{
    print $File::Find::name,"\n";
}

これを実行すると、次の出力が得られます。

Noob@Noob:~/tmp$ perl test.pl 
.
./test.txt
./test.pl
./test1.txt
./hello
./hello/temp.txt

今、私はno_chdir=>1、ディレクトリに遭遇した場合にディレクトリに入らないように設定することで、コードを作成することを考えていました。しかし、出力は、私のコードがhelloディレクトリに入り、そのファイルをリストしていることを明確に示しています。

では、どのようにコードを変更して、lsどのディレクトリにも入らないように動作させるにはどうすればよいですか。また./、ファイル/ディレクトリ名の前に表示されますが、削除できますか?

私はPerl5.14を使用しています。

4

4 に答える 4

16

$File::Find::pruneディレクトリへの再帰を回避するために使用できます。

use File::Find qw( find );

my $root = '.';
find({
   wanted   => sub { listfiles($root); },
   no_chdir => 1,
}, $root);

sub listfiles {
   my ($root) = @_;
   print "$File::Find::name\n";
   $File::Find::prune = 1  # Don't recurse.
      if $File::Find::name ne $root;
}

prune必要に応じて条件付きで設定できます。

use File::Basename qw( basename );
use File::Find     qw( find );

my %skip = map { $_ => 1 } qw( .git .svn ... );

find({
   wanted   => \&listfiles,
   no_chdir => 1,
}, '.');

sub listfiles {
   if ($skip{basename($File::Find::name)}) {
      $File::Find::prune = 1;
      return;
   }

   print "$File::Find::name\n";
}

no_chdir必要ではありません—それはあなたがやろうとしていることとは何の関係もありません—しかし私はそれがすること(cwdへの変更を防ぐ)が好きなので、私はそれを残しました。

于 2012-09-08T20:22:54.157 に答える
12

TLPの提案は、globまたはopendirあなたのケースに最適だと思いますが、別のオプションは、File :: Find :: Rule ( Find :: Fileのインターフェイス)を使用してディレクトリの再帰maxdepth(1)を停止することです。

use Modern::Perl;
use File::Find::Rule;

my $directory = '.';
my @files = File::Find::Rule->maxdepth( 1 )
                            ->file
                            ->name( '*.txt' )
                            ->in( $directory );
say for @files;

この場合、*.txtファイル名のみがに渡され@filesます。

サンプル出力:

A.txt
B.txt
columns.txt
data.txt
于 2012-09-08T20:44:18.307 に答える
4

これを行う最も簡単な方法は、preprocessパラメータを使用して、処理中の各ディレクトリからすべてのディレクトリを削除することです。つまり、検索対象として指定されたディレクトリの下に下がることはありません。

preprocessサブルーチンに渡されるパラメータリストは、現在のディレクトリ内のノード(の出力)ですreaddir。戻り値は同じリストですが、処理方法に従ってソートおよびフィルタリングされます。このコードはすべてのディレクトリを削除するだけです

イニシャルを削除する最良の方法は、から./を使用することです。ここで、を有効にすると、デフォルトで現在の作業ディレクトリがベースディレクトリになるため、コードが壊れることに注意してください。使用するとは、ベースディレクトリパラメータを明示的に渡すことを意味しますrel2absFile::Specno_chdirrel2absno_chdir

use strict;
use warnings;

use File::Find 'find';
use File::Spec;

find({ wanted => \&listfiles, preprocess => \&nodirs }, '.');

sub nodirs {
  grep ! -d, @_;
}

sub listfiles {
  my $filename = File::Spec->abs2rel($File::Find::name);
  print $filename, "\n";
}
于 2012-09-08T20:34:33.537 に答える
0

前処理と「必要なのnopを使用する

use File::Find qw( find );

my @f;

find(
{ 
    wanted => sub {},
    preprocess => sub {
        push(@f, grep !/^\.?\./,@_); # @_ is equivalent to readdir(DIR)
                                     # '.' and '..' come for free
        # find uses what you return here for processing. 
        # since nothing (an empty list) is returned, it has nothing to recurse on
     }
},
@dirs);

フルパスが必要な場合は、grepを次のようにマップします

push(@f, map { Spec->catfile($File::Find::dir,$_); } grep !/^\.?\./,@_);

あるいは単に

 push(@f, map { $File::Find::dir . '/' . $_); } grep !/^\.?\./,@_);

後者の場合、@ dirsの要素を指定する方法によっては、Windowsで\と/が混在する場合があります。

于 2016-05-01T09:03:47.933 に答える