¿Cómo leo en el contenido de un directorio en Perl?
file-io filesystems (8)
Aquí hay un ejemplo de recursión a través de una estructura de directorio y copia de archivos desde un script de copia de seguridad que escribí.
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";
}
¿Cómo logro que Perl lea el contenido de un directorio determinado en una matriz?
Backticks pueden hacerlo, pero ¿hay algún método que use ''scandir'' o un término similar?
Esto lo hará, en una línea (observe el comodín ''*'' al final)
@files = </path/to/directory/*>;
# To demonstrate:
print join(", ", @files);
Podría usar 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
proporciona una interfaz alternativa y más limpia para las opendir()
, closedir()
, readdir()
y rewinddir()
.
Similar a lo anterior, pero creo que la mejor versión es (ligeramente modificada) de "perldoc -f readdir":
opendir(DIR, $somedir) || die "can''t opendir $somedir: $!";
@dots = grep { (!/^/./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;
Una solución rápida y sucia es usar glob
@files = glob (''/path/to/dir/*'');
de: http://perlmeme.org/faqs/file_io/directory_listing.html
#!/usr/bin/perl
use strict;
use warnings;
my $directory = ''/tmp'';
opendir (DIR, $directory) or die $!;
while (my $file = readdir(DIR)) {
next if ($file =~ m/^/./);
print "$file/n";
}
El siguiente ejemplo (basado en un ejemplo de código de perldoc -f readdir) obtiene todos los archivos (no directorios) comenzando con un punto del directorio abierto. Los nombres de archivo se encuentran en la matriz @dots.
#!/usr/bin/perl
use strict;
use warnings;
my $dir = ''/tmp'';
opendir(DIR, $dir) or die $!;
my @dots
= grep {
/^/./ # Begins with a period
&& -f "$dir/$_" # and is a file
} readdir(DIR);
# Loop through the array printing out the filenames
foreach my $file (@dots) {
print "$file/n";
}
closedir(DIR);
exit 0;
closedir(DIR);
exit 0;
IO::Dir es agradable y proporciona una interfaz hash vinculada también.
Del 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";
}
Entonces podrías hacer algo como:
tie %dir, ''IO::Dir'', $directory_name;
my @dirs = keys %dir;
opendir(D, "/path/to/directory") || die "Can''t open directory: $!/n";
while (my $f = readdir(D)) {
print "/$f = $f/n";
}
closedir(D);
EDITAR: Oh, lo siento, me perdí la parte "en una matriz":
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: la mayoría de las demás respuestas son válidas, pero quería comentar específicamente esta respuesta , en la que se ofrece esta solución:
opendir(DIR, $somedir) || die "Can''t open directory $somedir: $!";
@dots = grep { (!/^/./) && -f "$somedir/$_" } readdir(DIR);
closedir DIR;
Primero, para documentar lo que está haciendo, ya que el póster no: está pasando la lista devuelta de readdir() a grep() que solo devuelve esos valores que son archivos (a diferencia de directorios, dispositivos, conductos con nombre, etc.) y eso no comienza con un punto (lo que hace que el nombre de la lista @dots
engañoso, pero eso se debe al cambio que realizó al copiarlo de la documentación de readdir ()). Dado que limita el contenido del directorio que devuelve, no creo que sea técnicamente una respuesta correcta a esta pregunta, pero ilustra un modismo común utilizado para filtrar nombres de archivo en Perl , y pensé que sería valioso documentarlo. Otro ejemplo visto mucho es:
@list = grep !/^/./.?$/, readdir(D);
Este fragmento lee todos los contenidos del manejador de directorio D excepto ''.'' y ''..'', ya que rara vez se desea utilizarlos en la lista.