Я хочу заново прочитать каталог, чтобы напечатать структуру данных на HTML-странице с помощью Template:: Toolkit.
Но я вишу, как сохранить пути и файлы в форме, которую можно легко прочитать.
Моя идея началась следующим образом
sub list_dirs{
my ($rootPath) = @_;
my (@paths);
$rootPath .= '/' if($rootPath !~ /\/$/);
for my $eachFile (glob($path.'*'))
{
if(-d $eachFile)
{
push (@paths, $eachFile);
&list_dirs($eachFile);
}
else
{
push (@files, $eachFile);
}
}
return @paths;
}
Как я могу решить эту проблему?
Ответ 1
Это должно сделать трюк
use strict;
use warnings;
use File::Find qw(finddepth);
my @files;
finddepth(sub {
return if($_ eq '.' || $_ eq '..');
push @files, $File::Find::name;
}, '/my/dir/to/search');
Ответ 2
Вы всегда должны использовать строгие и предупреждения, чтобы помочь вам отладить ваш код. Например, Perl предупредил бы вас, что @files
не объявлен. Но реальная проблема с вашей функцией заключается в том, что вы объявляете лексическую переменную @paths
для каждого рекурсивного вызова list_dirs
и не возвращаете возвращаемое значение после этапа рекурсии.
push @paths, list_dir($eachFile)
Если вы не хотите устанавливать дополнительные модули, возможно, вам поможет следующее решение:
use strict;
use warnings;
use File::Find qw(find);
sub list_dirs {
my @dirs = @_;
my @files;
find({ wanted => sub { push @files, $_ } , no_chdir => 1 }, @dirs);
return @files;
}
Ответ 3
Ответ mdom объясняет, как ваша первоначальная попытка сбилась с пути. Я также предлагаю вам рассмотреть более дружественные альтернативы File::Find
. CPAN имеет несколько вариантов. Здесь один.
use strict;
use warnings;
use File::Find::Rule;
my @paths = File::Find::Rule->in(@ARGV);
Также см. здесь:
И вот переписывание вашего рекурсивного решения. Что нужно отметить: use strict
; use warnings
; и использование блока видимости для создания статической переменной для подпрограммы.
use strict;
use warnings;
print $_, "\n" for dir_listing(@ARGV);
{
my @paths;
sub dir_listing {
my ($root) = @_;
$root .= '/' unless $root =~ /\/$/;
for my $f (glob "$root*"){
push @paths, $f;
dir_listing($f) if -d $f;
}
return @paths;
}
}
Ответ 4
Я думаю, что у вас есть проблема в следующей строке вашего кода.
for my $eachFile (glob($path.'*'))
Вы изменяете переменную $path в $rootpath.
Он правильно сохранит путь.
Ответ 5
Я использую этот script для удаления скрытых файлов (созданных Mac OS X) с моего USB Pendrive, где я обычно использую его для прослушивания музыки в машине и любого файла, заканчивающегося ".mp3", даже если он начинается с "._", будет отображаться в списке автомобильных аудио.
#!/bin/perl
use strict;
use warnings;
use File::Find qw(find);
sub list_dirs {
my @dirs = @_;
my @files;
find({ wanted => sub { push @files, $_ } , no_chdir => 1 }, @dirs);
return @files;
}
if ( ! @ARGV || !$ARGV[0] ) {
print "** Invalid dir!\n";
exit ;
}
if ( $ARGV[0] !~ /\/Volumes\/\w/s ) {
print "** Dir should be at /Volume/... > $ARGV[0]\n";
exit ;
}
my @paths = list_dirs($ARGV[0]) ;
foreach my $file (@paths) {
my ($filename) = ( $file =~ /([^\\\/]+)$/s ) ;
if ($filename =~ /^\._/s ) {
unlink $file ;
print "rm> $file\n" ;
}
}
Ответ 6
вы можете использовать этот метод в качестве рекурсивного поиска файлов, который разделяет определенные типы файлов,
my @files;
push @files, list_dir($outputDir);
sub list_dir {
my @dirs = @_;
my @files;
find({ wanted => sub { push @files, glob "\"$_/*.txt\"" } , no_chdir => 1 }, @dirs);
return @files;
}