Будущая программа будет состоять из определения рекурсивной процедуры
find
и её вызовов:
Perlsub find { my $name=shift; ❶ обработать имя$name
} find($_) for @ARGV; find('.') unless @ARGV;
Последняя строчка программы даст о себе знать, только если при запуске
программы не были указаны параметры (массив @ARGV
пуст).
Фрагмент ❶ разветвляет процедуру для трёх случаев:
когда $name
— имя директории, когда имя простого файла, и,
наконец, когда $name
не содержит ни того, ни другого (под
этот случай попадает имя несуществующего файла). Нам потребуются средства,
позволяющие по заданному имени определить, какому случаю оно соответствует.
Тут нам помогут встроенные операторы языка Perl -d и -f. Первый из них вычисляет истинное значение тогда и только тогда, когда его операнд — имя директории, второй, как нетрудно догадаться, когда операнд — имя обычного файла. Столь странный выбор имени операторов имеет причины, однако мы воздержимся от их объяснения. С учётом сказанного мы можем заменить фрагмент ❶ на следующий код:
Perlif(-d $name) { ❷ обработать имя директории$name
} elsif(-f $name) { print "$name\n"; } else { warn "$0: «$name»: $!\n"; }
Для получения оглавления директории используется примерно та же
последовательность действий, что и при считывания содержимого файла: открытие
и создание дескриптора директории — чтение в цикле из дескриптора — закрытие
дескриптора. Открытие и закрытие осуществляется встроенными процедурами
opendir
и closedir
. Для чтения из
дескриптора служит процедура readdir
.
Приступим к кодированию фрагмента ❷. Объявим
переменную $dir
для дескриптора директории. Пользуясь тем,
что в случае неудачи процедура opendir
возвращает ложное
значение, обработаем ошибку открытия директории:
Perlmy $dir; unless(opendir $dir, $name) { warn "$0: Невозможно открыть «$name»: $!\n"; return; }
Если открытие прошло успешно, займёмся обработкой в цикле объектов,
расположенных непосредственно в директории. Особые случаи — директории
.
и ..
— следует пропустить:
Perl$name='' if $name eq '/'; for(readdir $dir) { next if $_ eq '.' or $_ eq '..'; find("$name/$_"); }
Первая строчка — наша маленькая хитрость, решающая проблему корневой директории.
Наконец, закрываем дескриптор:
Perlclosedir $dir;