Perl'овка в домашнем хозяйстве
Илья Щуров Voyager, voyager@noo.ru
Все началось в далеком 1987 году, когда программисту Ларри
Уоллу надоело вручную делать то, что можно автоматизировать. Так и появился язык
Perl, предназначенный для обработки всевозможных log-файлов, извлечения из них
полезной информации и прочих нужд сисадмина юниксовой машины. В дальнейшем он
развился в нечто большее, а с приходом Интернета завоевал огромную популярность
как язык написания cgi-скриптов - форумов, гостевых книг, голосований и прочих
элементов интерактивности веб-сайтов. Для рядового программиста слова и
стали практически синонимами, и большинство статей на эту тему посвящено
именно веб-разработке. Многие пользователи Windows даже не догадываются, что
Perl можно использовать как-то иначе. А зря! Это очень удобный инструмент,
способный упростить жизнь во многих областях, даже далеких от
сайтостроительства. Главное - творческий подход.
Философия
Perl - язык со странностями. Это отмечает и его автор,
расшифровывая название как (дословно:
Патологически Эклектичный Мусорный Листер) вместо официального (Практичный язык для извлечения информации и
составления отчетов). Если знакомиться с Perl'ом после освоения С/C++, станет
немного не по себе, если же учить его в самом начале программистского пути,
будет еще хуже - приобретете кучу дурных привычек, ибо, объединив в себе
элементы множества других языков, Perl немного противоречив и не похож ни на что
другое. Однако в этом есть и своя прелесть.
Perl
призван максимально облегчить жизнь разработчика, поэтому очень многое из того,
что программист на С привык делать <руками>, здесь происходит автоматически.
Надоело преобразовывать переменные из строкового типа данных в числовой и
наоборот? Нет проблем - в Perl'е они вообще не отличаются: все <обычные>
переменные (не являющиеся массивами, файловыми дескрипторами и т. д.) имеют один
и тот же тип - скалярная величина. Строка <12> может выступать в роли числа 12 и
наоборот. Не надо следить за распределением памяти - если оперативной памяти
достаточно, можно скопировать хоть содержимое всего Интернета в одну переменную,
и не будет никаких <ошибок переполнения буфера> и связанных с ними дыр в
безопасности, столь любимых хакерами всех мастей. С массивами тоже все хорошо:
они меняют свой размер не менее автоматически, чем строки, и еще одной головной
болью становится меньше. Хеши (или ассоциативные массивы) - это вообще сказка,
ставшая былью: возможность создания наборов переменных, в которых элементы
индексируются не номерами, а произвольными строками, оказалась столь удобной,
что вся объектно-ориентированная часть языка построена именно на них. По сути,
хеши частично заменяют структуры языка C.
Особый разговор о регулярных выражениях. Повергающие в ужас
участки кода, вроде $str=~s/(\S{70})(\S+)/$1 $2/g; оказывается, являются не
только нечитаемым набором символов, но и весьма удобным инструментом,
позволяющим делать с текстом все, что только поддается формализации, и даже чуть
больше. Если коротко, то регулярные выражения - просто средство поиска и замены
участков строк, удовлетворяющих определенным шаблонам. Однако шаблоны эти могут
иметь довольно сложную структуру и определять весьма нетривиальные подмножества
строк. Скажем, регулярному выражению /(http:\/\/|www.)([a-zA-Z0-9-]
+\.)+[a-zA-Z0-9-]{2,4}/ будут соответствовать адреса сайтов, начинающиеся с
http:// или www., содержащие в себе только разрешенные символы и заканчивающиеся
двух-, трех- или четырехбуквенной доменной зоной. Более того, при замене можно
ссылаться на найденный текст или его участки - так, команда s/(\w+) (\w+)/$2 $1/
меняет местами пару слов, разделенных пробелом. Однако хватит о регулярных
выражениях - о них написаны целые книги (например, [2]), и углубляться в
подробности я не могу - места в журнале не хватит.
Во
многих случаях забота о программисте в Perl'е оказалась чрезмерной. Например,
отсутствие необходимости объявлять переменную перед ее использованием приводит к
тому, что одна опечатка может вылиться не в сообщение об ошибке, как в C, а во
многие часы отладки. Вместо того чтобы поругать невнимательного программиста,
как делают другие языки, когда встречают неизвестный ранее идентификатор, Perl
послушно создаст новую переменную и инициализирует ее нулем или пустой строкой
(в зависимости от контекста). Понятно, что если появление такой переменной -
результат опечатки, то это вряд ли входит в планы разработчика, и искать
подобную ошибку придется долго. Это же относится к ряду других вещей. Впрочем,
можно попросить Perl быть построже, использовав команду use strict; в самой
программе и ключ -w при запуске интерпретатора - именно так рекомендуют
поступать абсолютно все виденные мною руководства. Пожалуй, стоит прислушаться:
усилия, затраченные на самоконтроль, многократно окупятся временем,
сэкономленным на отладке.
Еще одна вещь в Perl'е, от которой у программиста с опытом
работы на <обычных> языках может случиться удар - это реализация
объектно-ориентированного подхода. Как такового понятия <объект> здесь вообще
нет, но есть хитрым образом сконструированная его замена1. Наследование, конструкторы, деструкторы, методы и прочие атрибуты
ООП - в наличии, хотя и в не совсем обычном виде. Гораздо хуже с такими вещами,
как защищенные (private или protected) методы и поля данных. Они просто
отсутствуют. Существуют некие соглашения о том, какие методы вызывать можно, а
какие - лучше не надо, но ничего похожего на строгие правила C++ и других языков
нет. Также нет никаких средств контроля типов данных. Ужас, одним словом. Но - к
этому можно привыкнуть и даже полюбить.
Увы, я уже не успеваю рассказать о списках и связанных с ними
контекстах, интерполяции, <умолчальных> переменных ($_ и @_), символических
ссылках и многом другом. Perl - язык богатый и необычный, у него есть сотни или
даже тысячи нюансов, которые можно почувствовать, только имея достаточный опыт
работы. Впрочем, для применения в <домашних условиях> знать их совсем не
обязательно.
1 (назад)Речь идет о Perl 5. Готовящийся к выходу
Perl 6 будет полностью объектно-ориентированным языком, но это уже другая
история.
Домохозяйство
Конечно, обычному пользователю обычной Windows-машины редко
приходится обрабатывать log-файлы или писать cgi-скрипты, но Perl может
пригодиться для решения куда более широкого круга задач. Вот несколько
примеров.
Однажды мне в руки попал диск, гордо именовавшийся <Музыкальной
энциклопедией Deep Purple>. В действительности - обычная mp3-коллекция, немного
сдобренная фотографиями, текстами песен, историей группы и кривой оболочкой. И
все бы ничего, да только дать человеческие имена каталогам и файлам разработчики
поленились, в результате чего mp3'шки назывались весьма загадочно:
- понятно, о какой песне идет речь? Как оказалось, информация
о названиях треков хранилась, во-первых, в id3-свойствах самих файлов, а
во-вторых - в лежащих в другом каталоге плей-листах. Мне же хотелось скопировать
весь диск в свою музыкальную коллекцию на винчестере, но так, чтобы все было
разложено по полочкам: имена файлов совпадали с названиями треков, а каталогов -
с альбомами. Разбираться с id3 не хотелось, зато формат плей-листов оказался на
удивление стандартным, и рука сама потянулась к Perl'у. В течение нескольких
минут написался скрипт, вытащивший информацию о названиях и скопировавший все в
правильном виде, а мне осталось лишь с ужасом представить, сколько бы я
проковырялся, вручную переименовывая сто тридцать один файл.
Через
некоторое время понадобилось перебросить часть музыкальной коллекции на карту
памяти Secure Digital для прослушивания с помощью Палма. Однако выяснилось, что
карманный компьютер не очень хорошо воспринимает русские имена файлов на
карточке, и, недолго думая, я решил их все транслитерировать. Естественно,
верный Perl был тут же вынут из ножен, написана и отлажена функция,
транслитерирующая любой текст (а после отладки сохранена в надежном месте -
вдруг еще пригодится), затем создан скрипт, рекурсивно ходящий по каталогам и
переименовывающий все, что содержит русские буквы в своем названии. После
запуска компьютер задумался. Подождав секунд двадцать, я снял приложение
perl.exe, добавил в скрипт несколько строчек, выводящих отладочную информацию,
запустил его еще раз и ужаснулся: из-за моей ошибки в коде он стал
транслитерировать имена ВСЕХ файлов на жестком диске. К счастью, много бед
наделать вышедшая из-под контроля программа не успела, но все же не могу не
предупредить: <Программер, в твоих руках великая сила, поэтому будь
осторожен!>
Впрочем, что я все о музыке да о музыке? Вот, например, история
о применении Perl'а в фотографии. Волею судьбы на мою голову свалился цифровой
фотоаппарат от Canon. При этом от удара в голове что-то повредилось, и теперь,
где бы я ни находился, мой мозг автоматически анализирует окружающую обстановку
на предмет композиции, освещения, выдержки, диафрагмы, баланса белого, глубины
резкости и т. п., а жесткий диск компьютера постоянно пополняется гигабайтами
отснятых кадров. История, которую я хочу рассказать, связана с одним из режимов
работы камеры - так называемым Stitch Assist mode, который помогает снимать
серии кадров для последующего их <склеивания> в одну панораму с использованием
стандартного софта от Canon. Полезный режим, надо сказать. Одна проблема: чтобы
скормить программе сделанные в нем снимки, их неплохо было бы для начала найти -
порой среди тысяч других кадров. Не слишком интересное занятие, однако тоже
легко поддающееся автоматизации. Дело в том, что камера записывает всевозможные
данные о параметрах съемки в специальные EXIF-свойства файла, в том числе и
режим. Поэтому достаточно взять какой-нибудь Perl-модуль, умеющий вытаскивать
эту информацию (я использовал Image-Info), написать скрипт, прогоняющий через
него все файлы каталога, и каким-либо образом отметить те из них, которые
содержат в EXIF'е слово . Пишется в течение пары минут!
Мне могут возразить, что можно было бы просто с помощью
стандартного поиска найти все jpg-файлы, содержащие слово (если
рассматривать их как текстовые), и не мучаться. Это, конечно, так, но с помощью
скрипта можно не только выделить кадры, снятые в определенном режиме, но и,
например, отсортировать их в порядке возрастания выдержки или убывания
диафрагмы, или автоматически переименовать их, добавив в имя какую-то информацию
о съемке, или сделать множество других полезных в хозяйстве вещей.
Еще одно занятие, для которого Perl подходит как нельзя лучше,
- обработка текстов из электронных библиотек. Там часто встречаются <порезанные
на строки> файлы в кодировке DOS, которые крайне неудобно печатать и читать - не
из-за кодировки (ее как раз несложно перевести в Win1251), а из-за оформления:
через каждые 80 символов в них начинается новая строка, а абзацы выделяются
несколькими пробелами (в отличие от стандартного Windows TXT, в котором строка
равна абзацу).
Борясь с подобными файлами, начинаешь ценить мощь и простоту
регулярных выражений. Программа, конвертирующая их в стандартный, опрятно
выглядящий HTML, занимает всего пару строчек кода. Еще пара строчек - и ее можно
использовать в пакетном режиме, натравливая на целые каталоги. Долой рутину!
На десерт расскажу о совсем необычном применении этого языка.
Однажды мне понадобилось проверить некоторое математическое утверждение,
относящееся ко взаимному расположению многомерных эллипсоидов. Самому думать
было лень, и я решил использовать для этих целей компьютер - чтоб не простаивал
зря. Каково же было мое удивление, когда я обнаружил, что пишу программу не на
C++ или Mathematica, а на вовсе не предназначенном для таких вещей Perl'е! Не
могу сказать, чтобы результат получился изящным, но он работал. А одно из
основных утверждений философии Perl так и звучит: <Если программа работает,
значит, она хорошая>.
Разумеется, я мог бы еще долго продолжать разговор об
использовании Perl'а в самых разных <бытовых> ситуациях, но не буду - полагаю,
что приведенных в статье примеров вполне достаточно, чтобы выразить основную
мысль: возможность в нужный момент быстро написать программу позволяет вам
решать множество нестандартных задач и дает реальную власть над компьютером и
информацией. Власть, за которую не надо бороться - достаточно просто освоить
Perl.
Практические советы
Несколько слов о том, где взять и как заставить
работать Perl. Будучи кроссплатформной open-source-разработкой, он
существует в версиях для Linux, различных Unix'ов, Mac и, конечно, Win32.
Дистрибутив под Windows развивает компания ActiveState - его можно скачать
с сайта www. activestate.com. После установки рекомендуется прописать
каталог, содержащий файл perl.exe, в переменную окружения Path, чтобы в
дальнейшем его можно было вызывать из командной строки - конечно, если
этого не сделал сам установщик. Perl - интерпретируемый язык,
предназначенный в первую очередь для работы с консолью, а не с графическим
интерфейсом, и с этим связаны некоторые тонкости при запуске ваших
собственных программ, написанных на нем. При установке интерпретатора все
pl-файлы связываются с perl.exe, и их можно запускать обычным образом -
кликая по иконке. Однако при этом вы, скорее всего, ничего не увидите -
быстро откроется консольное окошко, выдаст то, что сказал ваш скрипт, и
тут же закроется. Чтобы этого не происходило, можно завершать все свои
скрипты командой ожидания ввода <>;. Дойдя до этой строки,
интерпретатор остановится, вы сможете прочитать все, что он вам наговорил,
и лишь тогда позволить ему удалиться, нажав Enter. Впрочем, есть и
другие методы борьбы с закрывающимися окнами. Можно вызывать Perl из
командной строки, работая в каком-нибудь файловом менеджере, который еще
помнит, что это такое, - например, в FAR'е. У этого решения есть
существенное преимущество: возможность использования ключей, которых у
Perl'а в избытке - как и у любой другой программы, пришедшей из мира Unix.
Например, с помощью ключа -e можно писать короткие программы (в одну
строчку), вообще не сохраняя их в файл. Для этого достаточно набрать
что-то вроде perl -e "текст вашей короткой программы". Используя
подобные <однострочники> (one-liner), называемые также <заклинаниями>,
гуру Perl творят чудеса*. Если с командной строкой вы не дружны, можно предложить еще
один способ взаимодействия с интерпретатором: прикрутить его к
какому-нибудь текстовому редактору. Я использую для этих целей EditPlus 2
(http://www.editplus.com/), который
позволяет загружать различные схемы подсветки синтаксиса, создавать
пользовательские панели инструментов, подключать к себе сторонние средства
разработки, перехватывать выводимую ими информацию. Настроив его
соответствующим образом, можно запустить редактируемый Perl-скрипт
нажатием Ctrl+1, тут же увидеть выданные им сообщения, в случае ошибок
одним кликом перейти к строке, в которой она возникла, и вообще
значительно упростить общение с языком. Еще одна вещь, которую
необходимо знать: возможности Perl расширяются за счет установки новых
модулей. Модуль - это что-то вроде библиотеки функций, предназначенных для
выполнения какой-то определенной задачи. Их существует огромное
количество, практически под любую стандартную задачу можно найти уже
готовый модуль, и, что немаловажно, собраны они в одном месте: на сайте
CPAN (Comprehensive Perl Archive Network - http://www.cpan/. org; поиск доступен по
адресу search.cpan. org). Именно там я нашел функции для чтения
EXIF-информации из jpg-файлов.
* (назад)См.,
например,
gd.tuwien.ac.at/opsys/linux/gazette/issue90/okopnik.html. |
Литература и сетевые ресурсы
[1] С. Холзнер. Perl: специальный справочник. - <Питер>,
СПб, 2001. Лучшая, на мой взгляд, книга для человека, уже умеющего
программировать и собирающегося изучить Perl. В свое время читал ее как
художественную литературу - захватывает! [2] Дж. Фридл. Регулярные
выражения: библиотека программиста. - <Питер>, СПб, 2003. Второе издание
легендарной книги о регулярных выражениях. [3] http://www.dklab.ru/. Сайт посвящен скорее
вебмастерингу, нежели Perl'у, но там можно найти много полезной информации и по
языку. [4] http://www.cpan.org/.
Очень много всего для Perl - модули, документация, дистрибутивы и т.
д. [5] http://www.perldoc.com/. К
Perl'у прилагается обширная документация, которая вызывается запуском perldoc
(из командной строки) с нужным ключиком (рекомендую начать с perldoc perl). Ее
можно найти по этому адресу. В отличие от привычных хелпов, большинство статей
написаны довольно живым, даже веселым языком - правда, английским. Но это уже
мелочи.
|