Pytanie Jak czytać zawartość katalogu w Perlu?


Jak sprawić, by Perl odczytał zawartość danego katalogu w tablicy?

Backticks może to zrobić, ale czy jest jakaś metoda wykorzystująca "skandir" lub podobny termin?


33
2017-08-22 14:53


pochodzenie




Odpowiedzi:


opendir(D, "/path/to/directory") || die "Can't open directory: $!\n";
while (my $f = readdir(D)) {
    print "\$f = $f\n";
}
closedir(D);

EDYCJA: Oh, przepraszam, ominęła część "do tablicy":

my $d = shift;

opendir(D, "$d") || die "Can't open directory $d: $!\n";
my @list = readdir(D);
closedir(D);

foreach my $f (@list) {
    print "\$f = $f\n";
}

EDIT2: Większość innych odpowiedzi jest poprawna, ale chciałem skomentować ta odpowiedź w szczególności, w którym oferowane jest to rozwiązanie:

opendir(DIR, $somedir) || die "Can't open directory $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;

Po pierwsze, aby udokumentować, co robi, ponieważ plakat nie: przekazuje z powrotem zwróconą listę readdir () przez a grep () która zwraca tylko te wartości, które są plikami (w przeciwieństwie do katalogów, urządzeń, nazwanych potoków itp.) i które nie zaczynają się od kropki (co powoduje, że nazwa listy @dots wprowadza w błąd, ale wynika to ze zmian, które wprowadził podczas kopiowania z dokumentacji readdir ()). Ponieważ ogranicza zawartość katalogu, który zwraca, nie sądzę, że jest technicznie poprawną odpowiedzią na to pytanie, ale ilustruje wspólny idiom używany do filtrowania nazw plików w Perl, i pomyślałem, że warto byłoby udokumentować. Innym przykładem, który można zobaczyć, jest:

@list = grep !/^\.\.?$/, readdir(D);

Ten fragment kodu odczytuje całą zawartość z uchwytu D katalogu z wyjątkiem "." i "..", ponieważ są one bardzo rzadko pożądane do wykorzystania w aukcji.


48
2017-08-22 14:54





Szybkie i brudne rozwiązanie to użycie glob

@files = glob ('/path/to/dir/*');

12
2017-08-22 17:12



warto to zauważyć glob nie działa zgodnie z oczekiwaniami w przypadku spacji na ścieżce okna stackoverflow.com/questions/7898496/... - Kip
czasami brudne rozwiązania działają dobrze. - serenesat
Nie wykryje również ukrytych plików (zaczynających się kropką). - josch


IO :: Dir jest ładne i zapewnia również powiązany interfejs skrótu.

Od perldoc:

use IO::Dir;
$d = IO::Dir->new(".");
if (defined $d) {
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

tie %dir, 'IO::Dir', ".";
foreach (keys %dir) {
    print $_, " " , $dir{$_}->size,"\n";
}

Możesz zrobić coś takiego:

tie %dir, 'IO::Dir', $directory_name;
my @dirs = keys %dir;

8
2017-08-22 16:09





To zrobi to w jednym wierszu (zwróć uwagę na symbol wieloznaczny "*" na końcu)

@files = </path/to/directory/*>;
# To demonstrate:
print join(", ", @files);

6
2017-08-22 15:27



Czy ktoś może mi wyjaśnić, dlaczego jest to "złe"? Ponieważ jest czysty i prosty (w przeciwieństwie do innych rozwiązań), ale został pomijany bez wyjaśnienia. - rix0rrr
Ledwo pamiętam, że przeczytałem, że globbing zależy od używanej powłoki, może dlatego. - maaartinus
To najlepsze rozwiązanie, jest czyste i działało idealnie. - mikemeli
Nie działa dla perl 5.12 na Macu, ale działa z perłem 5.16. - kakyo


Możesz użyć DirHandle:

use DirHandle;
$d = new DirHandle ".";
if (defined $d)
{
    while (defined($_ = $d->read)) { something($_); }
    $d->rewind;
    while (defined($_ = $d->read)) { something_else($_); }
    undef $d;
}

DirHandle zapewnia alternatywny, czystszy interfejs do opendir(), closedir(), readdir(), i rewinddir() Funkcje.


5
2017-09-01 14:52





Oto przykład powtarzania struktury katalogów i kopiowania plików ze skryptu kopii zapasowej, który napisałem.

sub copy_directory {
my ($source, $dest) = @_;
my $start = time;

# get the contents of the directory.
opendir(D, $source);
my @f = readdir(D);
closedir(D);

# recurse through the directory structure and copy files.
foreach my $file (@f) {
    # Setup the full path to the source and dest files.
    my $filename = $source . "\\" . $file;
    my $destfile = $dest . "\\" . $file;

    # get the file info for the 2 files.
    my $sourceInfo = stat( $filename );
    my $destInfo = stat( $destfile );

    # make sure the destinatin directory exists.
    mkdir( $dest, 0777 );

    if ($file eq '.' || $file eq '..') {
    } elsif (-d $filename) { # if it's a directory then recurse into it.
        #print "entering $filename\n";
        copy_directory($filename, $destfile); 
    } else { 
        # Only backup the file if it has been created/modified since the last backup 
        if( (not -e $destfile) || ($sourceInfo->mtime > $destInfo->mtime ) ) {
            #print $filename . " -> " . $destfile . "\n";
            copy( $filename, $destfile ) or print "Error copying $filename: $!\n";
        } 
    } 
}

print "$source copied in " . (time - $start) . " seconds.\n";       
}

1
2017-08-22 15:36





Podobnie jak wyżej, ale myślę, że najlepsza wersja jest (nieznacznie zmodyfikowana) z "perldoc -f readdir":

opendir(DIR, $somedir) || die "can't opendir $somedir: $!";
@dots = grep { (!/^\./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;

1
2017-08-23 17:50