Эффективность поиска файлов с помощью Perl - PullRequest
1 голос
/ 30 марта 2011

Я пытаюсь получить массив файлов из дерева каталогов в скрипте Perl. Иногда я могу получить их с помощью расширения глобуса, но что-то, что мне нужно, это только с помощью регулярного выражения.

Например, я мог бы хотеть получить все файлы, которые соответствовали бы verify/*.finished с расширением оболочки. Использование glob(<pattern>) быстрее, чем сопоставление всего найденного с File::Find, когда я знаю глубину, на которой находится каталог проверки (например, glob("*/*/*/verify/*.finished"), но я немного застрял, когда мне нужно полагаться на сопоставление с регулярным выражением.

Есть ли способ получить эффективность glob с гибкостью регулярных выражений?

Ответы [ 4 ]

6 голосов
/ 30 марта 2011

Ну, вы можете просто сгенерировать полный список файлов с помощью glob, а затем grep результатов, используя регулярные выражения:

my @files = grep { /\.finished\z/ } glob '*/*/*/verify/*';

EDIT:

Если вопрос в том, есть ли средство, которое работает как glob, но использует регулярные выражения, я считаю, что ответ - нет. В общем случае я не вижу никакой альтернативы, кроме как пройти по всему дереву каталогов, и я сомневаюсь, что вы сможете добиться значительно большего успеха, чем File::Find.

2 голосов
/ 31 марта 2011

Возможно, проще всего вызвать систему find:

open(my $fh, "-|", find => ".", -type => "d", -name => "verify") or die "Err: $!";
while(<$fh>) {
  chomp;
  print "$_\n" for <$_/*.finished>;
}
close $fh or warn "Err: $!";
1 голос
/ 30 марта 2011

Я не уверен, что File::Find делает под капотом.(Это модуль XS?) Если он читает все содержимое каждого каталога и тестирует каждую запись индивидуально с помощью кода Perl, возможно, будет быстрее создать собственную команду find.Относительная эффективность glob может быть связана с тем, что внутренний цикл работает в C, а не в perl.

Вы можете оптимизировать, основываясь на том, что вы знаете о ваших файлах или критериях поиска.,Используя ваш пример, можно разбить его на два этапа:

  1. искать только каталоги и искать что-либо с точным именем "verify"
  2. искать *.finished вэти каталоги
0 голосов
/ 31 марта 2011

Вы можете попробовать что-то вроде этого:

glob '{' . join( ',', map { join( '/', ('*') x $_ ) } (1..9) ) . '}/verify/*';

не похоже, что производительность настолько хороша.Кроме того, если у вас есть несколько verify каталогов, он будет включать их все.

...