[Vienna-pm] find in several directories

Josef e9427749 at stud4.tuwien.ac.at
Tue Feb 19 10:42:24 PST 2008


Hi, allerseits!

Peter J. Holzer schrieb:
> On 2008-02-18 19:19:30 +0100, Baier Oliver wrote:
>> Josef hat mir vor einer Minute eine gleichwertige Lösung geschickt.
>>
>> Mein Problem dabei ist, dass ich File::Find bei dieser Variante
>> das Toplevel-Verzeichnis zur Suche übergeben müsste, was bei
>> Millionen von Dateien dann aber schnell recht mühsam wird.
> 
> Das ist aber in der allgemeinen Form Deines Problems (finde alle
> Directories, deren Pfad eine Regex R1 matcht, und darin alle Files,
> deren Name eine Reges R2 matcht) unvermeidlich. [...]
> d.h., Du musst das
> ganze Filesystem durchsuchen.
> [...] Aber das erfordert bereits eine inhaltliche Analyse der Regex,
> und das ist bei Perl-Regex halt schwierig.

Nun ja ich ging mal davon aus, dass er es ihm reicht wenn er
ein oder mehrere Startverzeichnisse angeben kann, also ungefähr
weiß wo er suchen soll und das es seinen Ansprüchen damit genügt.

Aber um auf das von Dir aufgebrachte allgemeinere Problem
einzugehen.
Noch ne Lösung mit File::Find::find's preprocess·Option.

Nochmal leicht abgeändert:
my $chkdirRE =qr'^/content(?:/nemat(?:/parts(/\d+(?:/tid\d*/?)?)?)?)?$';
# ^- test um festzustellen ob tiefer in das Verz. gegangen werden soll.
my $dirRE    =qr'^/content/nemat/parts/\d+/tid\d*/?$';
my $fileRE   =gr'^id\d+_\d+_(\d+)\.xml$';
my @startdirs=('/');
# v- ungetestet (nach wie vor)
use File::Find qw(find);
use Path::Class qw(dir);
my @result;
find { preprocess => sub { grep { !-d $_ ||
                                   dir($_)->absolute=~/$chkdirRE/¹ } @_
                          },
        wanted     => sub { push @result,$File::Find::name
                               if -f $_ && /$fileRE/ &&
                                  $File::Find::dir=~/$dirRE/²
                          }
      }, map { dir($_)->absolute } @startdirs;

print map "$_\n", @result;

ad 1) Oder in der Art $_=~$chkdirpartRE[$level] ...
ad 2) Unter bestimmten Umständen kann auf diese Zeile verzichtet
       werden...

Und schon saust File::Find nicht mehr durch unnötige Verzeichnisse.
In diesen Fall ist auch Path::Class::Iterator interessant.
Geht damit aber nachdem selben Schema.


>> Ich stelle mir vor, dass es irgendwo ein Pendant zu 'ls' gibt.
> ls sucht auch nur rekursiv durch. Falls Du das Pendent zum Shell
> Globbing meinst, das gibt es auch in Perl und heißt glob.

Diesen diesbezüglich wichtig Hinweis, lass ich mal so stehen.

pfiateng,
   Josef



More information about the Vienna-pm mailing list