2016-04-07 20 views
-5

Kennt jemand eine Methode, nach einer Datei in einer Verzeichnisstruktur zu suchen, ohne File::Find zu verwenden? Ich weiß Schritt für Schritt, wie es geht, aber wenn es möglich ist, es glatter zu machen, wird das hilfreich sein.Datei in Verzeichnisstruktur suchen

+0

Mögliches Duplikat von [Wie Dateien/Ordner rekursiv in Perl-Skript zu finden?] (Http://stackoverflow.com/questions/5089680/how-to-find-files-folders-recursively-in-perl -script) – Guido

+5

Was ist los mit 'File :: Find' ?! – Biffen

+0

Es gibt eine Vielzahl von Möglichkeiten, aber der Standard eingebaut ist wahrscheinlich der beste, aus allen möglichen Gründen. Entweder das oder 'File :: Find :: Rule'. Es gibt viele Probleme mit dem Verzeichnis-Traversal, über die Sie sich bei Verwendung eines Moduls keine Gedanken machen müssen. – Sobrique

Antwort

1

Von einem File::Find Hasser zum anderen: DirWalk.pm, durch die os.walk() Python inspiriert.

package DirWalk; 

use strict; 
use warnings; 

sub new { 
    my ($class, @dirs) = @_; 

    my @odirs = @dirs; 

    @dirs = qw/./ unless @dirs; 
    s!/+$!! for @dirs; 
    s!/+\.$!! for @dirs; 

    my $self = { _odirs => [@odirs], _dirs => [@dirs], _dhstack => [], _dnstack => [] }; 

    opendir my($dirh), $dirs[0]; 
    return undef unless $dirh; 
    shift @{ $self->{_dirs} }; 
    unshift @{ $self->{_dhstack} }, $dirh; 
    unshift @{ $self->{_dnstack} }, $dirs[0]; 

    return bless $self, $class; 
} 

sub _walk_op { 
    my ($self) = @_; 
    if (wantarray) { 
     my @ret; 
     while (defined(my $x = $self->next())) { 
      push @ret, $x; 
     } 
     return @ret; 
    } 
    elsif (defined wantarray) { 
     return $self->next(); 
    } 
    return undef; 
} 

sub next 
{ 
    my ($self) = @_; 
    my $dstack = $self->{_dhstack}; 
    my $nstack = $self->{_dnstack}; 
    if (@$dstack) { 
     my $x; 
     do { 
      $x = readdir $dstack->[0]; 
     } while (defined($x) && ($x eq '.' || $x eq '..')); 

     if (defined $x) { 
      my $nm = $nstack->[0].'/'.$x; 
      if (-d $nm) { 
       # open dir, and put the handle on the stack 
       opendir my($dh), $nm; 
       if (defined $dh) { 
        unshift @{ $self->{_dhstack} }, $dh; 
        unshift @{ $self->{_dnstack} }, $nm; 
       } 
       else { 
        warn "can't walk into $nm!" 
       } 
       $nm .= '/'; 
      } 
      # return the name 
      return $nm; 
     } 
     else { 
      closedir $dstack->[0]; 
      shift @$dstack; 
      shift @$nstack; 
      unless (@$dstack) { 
       while (@{ $self->{_dirs} }) { 
        my $dir = shift @{ $self->{_dirs} }; 
        opendir my($dirh), $dir; 
        next unless defined $dirh; 
        unshift @{ $self->{_dhstack} }, $dirh; 
        unshift @{ $self->{_dnstack} }, $dir; 
        last; 
       } 
      } 
      return $self->next(); 
     } 
    } 
    else { 
     return undef; 
    } 
} 

use overload '<>' => \&_walk_op; 
use overload '""' => sub { 'DirWalk('.join(', ', @{$_[0]->{_odirs}}).')'; }; 

1; 

Beispiel:

# prepare test structure 
mkdir aaa 
touch aaa/bbb 
mkdir aaa/ccc 
touch aaa/ccc/ddd 

# example invocation: 
perl -mDirWalk -E '$dw=DirWalk->new("aaa"); say while <$dw>;' 

#output 
aaa/ccc/ 
aaa/ccc/ddd 
aaa/bbb 

Ein weiteres Beispiel:

use strict; 
use warnings; 
use DirWalk; 

# iteration: 
my $dw = DirWalk->new("aaa"); 
while (<$dw>) { 
    print "$_\n"; 
} 

# or as a list: 
$dw = DirWalk->new("aaa"); 
my @list = <$dw>; 
for (@list) { 
    print "$_\n"; 
} 
+1

Welche Vorteile hat dies gegenüber der bereits erwähnten Datei :: Find :: Rule? – ikegami

+3

@PopescuEmanuel: Sie können also keine Kernmodule aus der Perl-Installation oder die bewährten von CPAN verwenden, aber es ist in Ordnung, ein unbekanntes und ungetestetes Modul von einem zufälligen Ort im Internet zu kopieren und zu verwenden.Das ist seltsame Sicherheit – Borodin

+1

@ikegami, wenn Sie mich fragen. 'File :: Find :: Rule' ist eine große unordentliche Sache, die nicht standardmäßig installiert ist. Während mein 'WalkDir' eine kleine Sache ist, die ich bei Bedarf anpassen kann. Außerdem läuft das 'WalkDir' tatsächlich auf dem Baum, während Sie darüber iterieren: Es wird nicht alles in die Liste aufgenommen, wie' File :: Find :: Rule'. Aber persönlich habe ich nichts gegen die 'File :: Find :: Rule', außer dass ich sie nicht benötigte, wenn ich sie brauchte. – Dummy00001

2

Datei :: Finden ist ein Kernmodul seit Perl 5.000, so sehe ich keinen Grund dafür, es nicht zu verwenden.

Aber wenn Sie immer noch Ihren verrückten Weg nehmen möchten, können Sie den find Befehl aufrufen.

0

Die Methode, die ich habe inplamenting drei Befehle verwendet: opendir, readdir und closedir. Siehe unten für ein Beispiel:

opendir my $dir1, $cwd or die "cannot read the directory $cwd: $!"; 
@cwd= readdir $dir1; 
closedir $dir1; 
shift @cwd; shift @cwd; 
foreach(@cwd){if ($_=~/$file_search_name/){print "I have found the file in $_\n!";}} 

Das Verzeichnis wird in @cwd gespeichert, das enthält. und .. Für Windows wird shift @cwd diese entfernen. Ich bin leider knapp für die Zeit, aber nutzen Sie diese Idee mit einem Anon-Array zum Speichern der Verzeichnis-Handles sowie ein anderes Array zum Speichern der Verzeichnispfade. Vielleicht verwenden Sie -d, um zu prüfen, ob es ein Verzeichnis ist. Es könnte Probleme mit der Dateiberechtigung geben, also vielleicht, wenn (opendir ...) eine gute Option wäre.

Viel Glück.

0

Ich bin sicher, dass ich für diese Antwort lebendig geschändet werden wird, aber Sie könnten immer entweder system() oder backticks `` verwenden, um den regulären Linux-Suchbefehl auszuführen. Oder haben eine Art von ls ...

@files = `ls $var/folder/*.logfile` 
@files = `find . -name $file2find` 

Ich erwarte, dass einige erfahrene perlers haben viele gute Gründe, dies nicht zu tun.

0

yon kann auch sowas ausprobieren !!!

# I want to find file xyz.txt in $dir (say C:\sandbox) 

    Findfile("xyz.txt", $dir); 

    sub Findfile() 
    { 
     my $file = shift; 
     my $Searchdir = shift; 

     my @content = <$Searchdir/*>; 

     foreach my $element (@content) 
     { 
      if($element =~ /.*$file$/) 
      { 
       print "found"; 
       last; 
      } 
      elsif (-d $element) 
      { 
       Findfile($file, $element); #recursive search 
      } 
     } 

    } 
+1

Willkommen bei _StackOverflow_, bevor Sie dies tun können, lesen Sie [wie Sie eine Antwort schreiben] (http://stackoverflow.com/help/how-to-answer). Geben Sie ein wenig Kontext an und erklären Sie, warum Sie diesen Code veröffentlicht haben und was er tut. Denken Sie auch daran, sich die Zeit zu nehmen, um Ihre Antwort so zu formatieren, dass sie für die Leser leicht verständlich ist. – Nacho