Прогулка по файловой системе Наверняка



Обход файловой системы при помощи модуля File::Find

Теперь, когда вы познакомились с основами просмотра файловой системы, покажем более быстрый и изящный способ сделать то же самое. В Perl есть модуль F; ie: : Fi nd, позволяющий эмулировать команду find из Unix. Самый простой способ начать работать с этим модулем - воспользоваться командой find2perl для генерирования кода-прототипа Perl.

С flnd2perl не всегда легко работать в Perl в отличных от Unix-системах. Для ее выполнения пользователям MacOS, например, понадобится Macintosh Programmer's Workshop (MPW) либо им придется изменить исходный код, чтобы получать ffARGV в диалоговом окне. Вот пример кода, позаимствованный у Криса Нандора (Chris Nandor), соавтора «MacPerl: Power and Ease» (MacPerl: Сила и легкость):

@ARGV = @ARGV 9 @ARGV :

split '\s". MacPerl: :Ask( "Arguments'7' );

Во всех перенесенных версиях есть модуль File; Fid, который используют команды find2perl и find.pl, так что ото не должно стать проблемой. Позже в этой главе мы покажем, как вызвать его напрямую.

Предположим, что вам нужна программа для поиска файлов beeskneen в каталоге /home. Вот командная строка, использующая команду Unix find:

% find /home -name beesknees -print

Передадим те же параметры команде find2perl:

% find2perl /home -name beesknees -print и получим:

S'/usr/bin/oerl

eval 'exec /usr/bin/perl -S $0 ${1 + 'W}' if Srunning under some shell;

require "find.pl";

ff Обходим нужные файловые системы

&find('/home'):

exit;

sup wanted {

/"bee^kneesS/ && p--irt("$narrev' ';.

}

Код, сгенерированный командой find2perl, довольно прямолинеен. Он загружает необходимую библиотеку find.pl при помощи оператора require, затем вызывает подпрограмму &гinc() с именем начального каталога. Вскоре мы обсудим назначение подпрограммы &war'terj( ), поскольку именно здесь будут находиться все интересные изменения, которые мы хотим изучить. Перед тем как вносить изменения в этот код, важно обратить внимание на те немногие моменты, которые могут не показаться очевидными при рассмотрении приведенного фрагмента:

  • Те, кто работал над модулем File: :Find, столкнулись с проблемой переносимости этого модуля на другие платформы. Внутренние подпрограммы модуля File: : Find действуют так, что один и тот же код работает и в Unix, и в MacOS, и в NT, и в VMS и т. д.
  • Хотя код, сгенерированный find2perl, на первый взгляд похож на код Perl 4 (например, тут используется require для загрузки файла .pi), find.pl в действительности устанавливает несколько псевдонимов из PerlS. Обычно бывает полезно заглянуть «под завесу», прежде чем использовать модуль в собственной программе. Если вам нужен исходный код модуля, уже установленного в системе, то, выполнив команду perl -F или следующую команду, вы получите список каталогов стандартных библиотек:

% perl-e 'print join("\n",@INC,"")'

Давайте поговорим о подпрограмме &wanted(), которую мы изменим для своих нужд. Подпрограмма &wanted() вызывается для каждого найденного &find() (или &File: : Find: :f ind(), чтобы быть точным) файла или каталога при обходе файловой системы. Именно код из &war': j(} должен выбирать «интересные» файлы или каталоги и работать с ними. В примере, приведенном выше, сначала проверяется соответствие имени файла или каталога строке beesknees. Если они совпадают, оператор && заставляет Perl выполнить оператор print, чтобы вывести имя найденного файла.

При создании собственных подпрограмм &wanted() нам придется учитывать два практических момента. Поскольку &w,,nted() вызывается по одному разу для имени каждого файла или каталога, важно сделать этот код коротким и аккуратным. Чем быстрее мы сможем выйти из подпрограммы &warted(), тем быстрее find сможет перейти к новому файлу или каталогу и тем быстрее будет выполняться вся программа. Также важно иметь в виду «закадровые» соображения совместимости, о которых мы недавно упоминали. Было бы позором одновременно иметь переносимый вызов &fina() и системно-зависимую подпрограмму &wanted() (кроме случаев, где этого невозможно избежать). Несколько подсказок, помогающих избежать такой ситуации, можно получить, посмотрев на текст модуля File: : Find.

Для первого использования модуля File:: Find давайте перепишем пример, созданный для удаления core-файлов, и затем немного его расширим. Для начала наберем:

# find2perl -name core -print что даст нам следующее: require "! ind.pi"

&find('. ' ) exit,

sub wanted !

/"coreS/ && DrintC'Sname^i"):

}

Затем мы добавим -s к строке вызова Perl и изменим подпрограмму

&wanted():

sub wanted (

/"core$/ && prin+("$i>ame\n") && dpfired $r && ::nifik($rapf4;

При вызове программы с ключом -г мы получаем необходимую нам функцию (удаление core-файлов). Внесем небольшое изменение, добавляющее некоторую степень защиты нашему потенциально разрушительному коду:

oud wanted {

/"coreS/ && -s $nairie *& print("$name\n") &&

defined $r s& i;nlink($name); }

Теперь, перед тем как выводить имя файла или удалять его, мы проверяем, не является ли размер файла core нулевым. Некоторые пользователи иногда создают ссылку на /dev/null с именем core в своем домашнем каталоге, чтобы core-файлы в нем не сохранялись. Параметр —s указывается для того, чтобы убедиться, что по ошибке не будут уда лены ссылки или файлы нулевой длины. Если мы хотим действовать осторожнее, нам следует выполнить еще две дополнительные проверки:

  1. Открыть файл и убедиться, что этот файл действительно является core-файлом. Сделать это можно как из Perl, так и вызвав команду Unix file. Определить, что файл действительно является core-файлом, может оказаться достаточно сложно в случае, если файловые системы смонтированы по сети с компьютерами другой архитектуры с иными форматами core-файлов.
  2. Посмотреть на время изменения файла. Если кто-то в настоящий момент отлаживает программу, используя файл core, он вряд ли обрадуется, если вы утащите этот файл прямо «из-под нее».

Давайте на время отдохнем от мира Unix и посмотрим на примеры, имеющие отношение к MacOS и Windows NT/2000. Ранее в этой главе я уже говорил, что в MacOS у каждого файла есть два атрибута - созда телъ и тип, позволяющие операционной системе определить, какое приложение создало этот файл и какого он типа. Эти атрибуты хранятся в виде четырехсимвольных строк. Например, для текстового документа, созданного приложением SimpleText, эти атрибуты будут иметь значения ttxt (для создателя) и TEXT (для типа). Из Perl (только для MacPerl) мы можем получить эту информацию при помощи функции MacPerl: :GetFileInfo(). Синтаксис ее таков:

$type = MacPerl::GetFileInfo(filename); или:

($creator,$type) = MacPerl::GetFileInfo(filename); Чтобы найти все текстовые файлы в файловой системе MacOS, мы можем выполнить следующее:

use File::Find;

&File::Find::find(\&wanted,"Macintosh HD:");

sub wanted{ -f $_ && MacPerl;:GetFileInfo($_) eq "TEXT" &&

print "$Find::File::name\n"; }

Вы, должно быть, заметили, что это выглядит немного иначе, чем наши предыдущие примеры. Однако действует этот код точно так же. Мы просто вызываем процедуры из File: :Find напрямую, без find.pl. Кроме того, мы используем переменную $name, определенную в пространстве имен File: :Find, чтобы вывести абсолютный путь файла, а не только его имя. Взгляните на полный список переменных, определяемых File: : Find при обходе файловой системы (табл. 2.2).



- Начало - - Назад - - Вперед -