Анимация
JavaScript
|
Главная Библионтека 9.6. Получение списка файлов по шаблону 335 9.6. Получение списка файлов по шаблону Проблема Требуется получить список файлов по шаблону, аналогичному конструкциям ... (MS-DOS) и ..h (UNIX). Решение Семантика командного интерпретатора С shell системы UNIX поддерживается в Perl с помощью ключевого слова glob и оператора <>: @list = <..с>; @list = glob("..c"); Для ручного извлечения имен файлов можно воспользоваться функцией readdi г: openclir(DIR, $path); @files = grep { /\,с$/ } readdir(DIR); closedir{DIR); Модуль File::KGlob от CPAN получает список файлов без ограничений длины: use File:;KGlob; @files = glob("..c"); Комментарий Встроенная функция Perl glob и запись <ШАБЛОН> (не путать с записью <МАНИПУ-ЛЯТОР>!) в настоящее время на большинстве платформ используют внешнюю программу для получения списка файлов. В UNIX это программа csh\ а в Windows - dosglob.exe. На Macintosh и в VMS это реализуется на внутреннем уровне, без внешних программ. Предполагается, что шаблоны обеспечивают семантику С shell во всех системах, отличных от UNIX, и улучшают переносимость. Из-за использования интерпретатора в UNIX такое решение не подходит для сценариев с атрибутом set и id. Чтобы справиться с затруднениями, можно реализовать собственный механизм отбора с применением встроенного оператора opendir или модуля File::KGlob от CPAN - в обоих случаях внешние программы не используются. File::KGlob обеспечивает семантику отбора по типу интерпретаторов UNIX, тогда как opendir позволяет отбирать файлы с помощью регулярных выражений Perl. В простейшем решении с opendir список, возвращаемый readdir, фильтруется с помощью grep: @files = grep { /\.[ch]$/i } readdir(DH): Обычно при наличии установленного интерпретатора tcsh Perl использует его, поскольку он надежнее. Если не установлен ни один из этих интерпретаторов, используется /bin/sh>. То же самое можно сделать и с помощью модуля DirHandle- use DirHandle, $dh = DirHandle->new($path) or die Can t open $path $\n , @files = grep { /\ [ch]$/i } $dh->read(), Как обычно, возвращаемые имена файлов не содержат каталога. При использовании имени каталог приходится присоединять вручную: opendir(DH, $dir) or die Couldn t open $dir for reading $i , @files = 0 while( defined ($file = readdir(DH)) ) { next unless /\ [ch]$/i my Ifilename = $dir/$file , push(@files, $filename) if -T $file, В следующем примере чтение каталога и фильтрация для новыщения эффективности объединяются с преобразованием Шварца (см. главу 4 «Массивы»). В массив @dirs заносится отсортированный список подкаталогов, имена которых представляют собой числа: @dirs = map { $ ->[1] } # Извлечение имен sort { $а->[0] <=> $Ь->[0] } # Числовая сортировка имен grep { -d $ ->[1] } # Каталоги тар { [ $ , $path/$ ] } # Сформировать (имя, путь) grep { /"\d+$/ } « Только числа readdir(DIR), # Все файлы В рецепте 4.14 показано, как читать подобные странные конструкции. Как обычно, форматирование и документирование кода заметно упрощает его чтение и понимание. t> Смотри также- Описание функций closedir, opendir, readdir, rewinddir, seekdir и telldir в perlfunc(l); документация но стандартному модулю DirHandle; раздел «I/O Operators» perlop(i); рецепты 6.9; 9.7. 9.7. Рекурсивная обработка всех файлов каталога проблема Требуется выполнить некоторую операцию с каждым файлом и подкаталогом некоторого каталога. Решение Воспользуйтесь стандартным модулем File::Find. 9.7. Рекурсивная обработка всех файлов каталога 337 use File Find, sub process file { # Делаем то, что хотели find(\&process file, @DIRLIST), Комментарий Модуль File::Find обеспечивает удобные средства рекурсивной обработки файлов. Просмотр каталога и рекурсия организуются без вашего участия. Достаточно передать find ссылку на функцию и список каталогов. Для каждого файла в этих каталогах find вызовет заданную функцию. Перед вызовом функции find переходит в указанный каталог, имя которого по отношению к начальному каталогу хранится в переменной $File Find dir. Переменной $ присваивается базовое имя файла, а полный путь к этому файлу находится в переменной $File Find name. Ваша программа может присвоить $File Find prune истинное значение, чтобы функция find не спускалась в только что просмотренный каталог. Использование File::Find демонстрируется следующим простым примером. Мы передаем find анонимную подпрограмму, которая выводит имя каждого обнаруженного файла и добавляет к именам каталогов /: @ARGV = qw( ) unless @ARGV use File Find, find sub { print $File Find name, -d && / , \n }, @ARGV, Для вывода / после имен каталогов используется оператор проверки -d, который при отрицательном результате возвращает пустую строку . Следующая программа выводит суммарный размер всего содержимого каталога. Она передает find анонимную подпрограмму для накопления текущей суммы всех рассмотренных ей файлов. Сюда входят не только обычные файлы, но и все типы индексных узлов, включая размеры каталогов и символических ссылок. После выхода из функции find программа выводит накопленную сумму. use File Find, @ARGV = С ) unless @ARGV, my $sum = 0, find sub { $sum += -s }, @ARGV, print @ARGV contains $sum bytes\n , Следующий фрагмент ищет самый большой файл в нескольких каталогах: use File Find, @ARGV = ( ) unless @ARGV, my ($saved size, $saved name) = (-1, ), sub biggest { return unless -f && -s > $saved size, $saved size = -s $saved name = $File Find name, find(\&biggest, @ARGV), print Biggest file $saved name in @ARGV is $saved size bytes long \n , 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 [ 106 ] 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |