Рекурсивный обход каталога в Perl - PullRequest
3 голосов
/ 27 февраля 2012

Я пытаюсь написать скрипт, который распечатывает файловую структуру, начиная с папки, в которой находится скрипт. Скрипт работает нормально без рекурсивного вызова, но при этом вызове он печатает содержимое первой папки и вылетает с следующее сообщение: closedir () попытался использовать недопустимый dir-дескриптор DIR в строке printFiles.pl 24. Папки печатаются, и выполнение достигает последней строки, но почему не выполняется рекурсивный вызов? И как я должен решить это вместо этого?

 #!/usr/bin/perl -w

printDir(".");
sub printDir{
opendir(DIR, $_[0]);
local(@files);
local(@dirs);
 (@files) = readdir(DIR);
 foreach $file (@files) {
    if (-f $file) {
      print $file . "\n";
    }
    if (-d $file && $file ne "." && $file ne "..") {
      push(@dirs, $file);
    }
 } 
 foreach $dir (@dirs) {
   print "\n";
   print $dir . "\n";
   printDir($dir);
 }
 closedir(DIR);
}

Ответы [ 3 ]

7 голосов
/ 27 февраля 2012
  • Вы всегда должны use strict; и use warnings; в начале вашей программы Perl, особенно перед тем, как обращаться за помощью.Таким образом, Perl покажет много простых ошибок, которые вы можете не заметить иначе.

  • Ошибка недопустимого дескриптора файла , вероятно, потому что DIR является глобальным каталогомобработать и был закрыт уже при предыдущем выполнении подпрограммы.Лучше всегда использовать лексические дескрипторы как для файлов, так и для каталогов, а также проверять код возврата, чтобы убедиться в успешном открытии, например:

    opendir my $dh, $_[0] or die "Failed to open $_[0]: $!";
    

    Одним из преимуществ лексических дескрипторов файлов является то, что они закрываются неявнокогда они выходят из области видимости, вам не нужен ваш вызов closedir в конце подпрограммы.

  • local не предназначен для такого использования.В качестве декларации этого недостаточно, и вы создаете временную копию глобальной переменной, к которой имеет доступ все.Лучше всего использовать my вместо этого, например,

    my @dirs;
    my @files = readdir $dh;
    
  • Кроме того, имена файлов, которые вы используете из readdir, не имеют пути, и поэтому ваши тесты файлов не пройдут, если вылибо chdir в обрабатываемом каталоге, либо добавьте строку пути к имени файла перед тестированием.

3 голосов
/ 27 февраля 2012

Почему бы не use File::Find?

use strict; #ALWAYS!
use warnings; #ALWAYS!
use File::Find;

find(sub{print "$_\n";},".");
3 голосов
/ 27 февраля 2012

Используйте модуль File :: Find .Обычно я делаю это с помощью инструмента find2perl , который поставляется с perl, который принимает те же параметры, что и find , и создает подходящий скрипт perl с помощью File :: Find.Затем я настраиваю сгенерированный скрипт, чтобы сделать то, что я хочу.Но также возможно использовать File :: Find напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...