Однострочник месяца на Perl: Приключение с произвольными архивами
Автор: Ben Okopnik
Перевод: Павел Соколов


Весна была в самом разгаре и Вумерт Фунли получал удовольствие от ещё одного прекрасного дня. Это заключало в себе тривиально простое конфигурирование Linux кластера из 1000 узлов, а теперь доводилось до логического завершения обедом из марокканской б'стиллы (b'stilla), приправленной щепоткой смеси рас-эль-ханут (ras el hanout), и фруктового кускус, дополняемого десертом из сладкого риса с корицей. Всё было так мирно... пока не вломился Фринк Ублик, поддерживая, вернее, почти неся, мужчину, который находился в крайней степени шока. Фринк помог ему расположиться на софе и обессиленный своими усилиями упал на лёгкий стул.

-- Вумерт, это просто скандал! Это Резолв Дот Конф, простой... м-м-м, скажем, сисадмин. Недавно его жесточайшим образом заставили установить какую-то из древних ОС на компьютер его менеджера - ты можешь представить? И теперь его просят сделать то, что звучит уж совсем невозможным, хотя я знаю только отдельные детали. Он слышал о твоей репутации (а кто сегодня не слышал?), и пришёл узнать, сможешь ли ты помочь ему, но свалился на улице прямо перед твоей дверью от остаточного шока и острого дефицита Джолт Колы. Что до проблемы, то я дам ему возможность самому описать её.

Вумерт присматривал за своим гостем пока слушал, в результате последний теперь выглядел почти нормально. Несомненно, "кофе сисадминского градуса по-вумертовски" было широко известно среди cognoscenti (знатоков) своими восстановительными свойствами, хотя точный рецепт (по общему мнению, в предках у него были эспрессо Александр и кофе с мороженым, но по остальным деталям различные теории расходились) сохранялся в глубоком секрете.

Теперь, однако, взгляд известного детектива заострился до того состояния концентрации, которое он обычно принимал во время работы.

-- Пожалуйста, изложите свою проблему чётко и лаконично.

Быстро оправляющийся сисадмин печально потряс головой.

-- Хорошо, мистер Фунли...видите ли, у меня есть скрипт для обработки данных, присылаемых нам филиалами. Дело в том, что все они приходят в разных форматах: мы занимаемся обработкой данных медицинского страхования и у каждой страховой компании формат свой. Более того, способ пересылки у всех тоже разный: некоторые присылают просто файл с данными, другие используют "gzip" или "compress", или "bzip", или "rar", или даже "tar" и "compress" (или "gzip"), а третьи (к счастью все из них приходит в виде простых файлов с данными) - отдают нам просто поток из программ их собственной разработки. Имея спецификации, наши программисты разобрались с конвертацией данных из разных форматов, однако проблема произвольного типа сжатия была оставлена для решения мне и я выбился из сил, решая её.

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

--В любом случае, на данный момент обработка всё ещё требует человеческого вмешательства. Два человека занимаются только сортировкой и разархивированием файлов весь день напролёт. Если бы не это, вся система могла бы быть полностью автоматизирована... и, конечно, менеджмент продолжает наседать: "Почему с этим ещё не разобрались? Разве компьютерщики не должны..." и так далее.

Когда он наконец сел и посмотрел на Вумерта, его губы были плотно сжаты. Определённо, он смирился со своей судьбой, как бы ужасна она ни была.

--Будьте честны со мной, Мистер Фунли. Возможность решения существует, или мне конец? Конечно, я знаю Мантру[1], но я бы хотел продолжать работу, если возможно. Я нужен моим пользователям и я знаю о Тёмных Силах, которые готовы поработить их невинные души если не будет сисадмина, способного их защитить.

Вумерт кивнул, подтверждая, что слова старого усталого воина абсолютно истинны. Он также сталкивался и бился с Тёмными - созданиями, которые создали бы сумятицу в головах пользователей, если бы их выпустили хоть на минуту, и тоже знал доблестную Гильдию Сисадминов (http://sage.org), которая поклялась защищать невиновных (даже если, как это часто бывает, от себя самих, применяя мистический и святой УРОН[2]).

-- Резолв, мне очень приятно сказать тебе, что решение проблемы действительно существует. Я уверен, что Вы провели исследование по поводу существующих инструментов и конечно слышали об "atool", менеджере архивов, написанном Oskar Liljeblad...

После кивка Резолва он продолжил.

-- Хорошо, тогда вы также знаете, что он может обработать все эти форматы архивов и даже больше. Несмотря на то, что эта программа написана на Perl, мы не будем использовать части её кода в нашем скрипте - это была бы бесполезная трата сил. Вместо этого, мы воспользуемся "acat", одной из утилит пакета"atool", в качестве внешнего фильтра - условного. Всё, что нам надо сделать - это вставить её прямо в начало нашего скрипта, примерно так:


#!/usr/bin/perl -w
# Создан Резолв Дот Конф в укольник, 43 день месяца хаоса, 3166 г. YOLD

@ARGV = map { /\.(gz|tgz|zip|bz2|rar|Z)$/ ? "acat $_ '*' 2>/dev/null|" : $_ } @ARGV;
# остальная часть скрипта
...


-- Perl позаботится о соответствующей магии - и это решит проблему.

Через секунду сисадмин был снова на ногах, ожесточённо тряся руку Вумерта.

-- Мистер Фунли, я не знаю, как благодарить Вас. Вы спасли...хорошо, я не буду об этом. Но знайте, что теперь у Вас есть друг, куда бы меня ни занесло. Теперь они увидят это!... И, только чтобы убедиться, что я понял - что это? Как оно работает?

Вумерт взглянул на Фринка, который также ёрзал на стуле в ожидании объяснения.

-- Что ты думаешь, Фринк, ты с этим разберёшься? Я использовал только одну функцию и один оператор. Остальное получилось автоматически, просто из-за способа работы Perl с файлами и командной строкой.

Фринк немного покраснел и пожевал большой палец, как он это обычно делал, когда нервничал.

-- Ну, Вумерт...Я знаю, ты сказал мне изучить функцию "map", но она оказалась довольно сложной, я потерялся в самом начале, а потом вышел этот новый фильм...

Вумерт улыбнулся и потряс головой.

-- Хорошо. "map", как говорится в "perldoc -f map", вычисляет приведённое выражение или блок выражений для каждого элемента списка - это вроде цикла "for", но гораздо короче и более удобно в большинстве случаев. Я также воспользовался тройным условным оператором (ternary conditional operator) ("?:"), который работает также, как конструкция "if-then-else":


# Тройной условный оператор - присваивает $a значение 5, 
# если $b истинно, либо 10 в противоположном случае
$a = $b ? 5 : 10;

# конструкция "if-then-else" - действие то же самое
if ( $b ){
        $a = 5;
}
else {
        $a = 10;
}

-- Оба приведённых выше варианта делают одно и то же, но, опять же, первый способ короче и часто более удобен. Если мы рассмотрим, что делает написанный мной скрипт по шагам, то увидим, что он тестирует каждый элемент @ARGV, в котором сначала находится всё содержимое командной строки после имени скрипта, на соответствие следующему регулярному выражению:

/\.(gz|tgz|zip|bz2|rar|Z)$/

Оно подойдёт к любому имени файла, который заканчивается на точку, за которой следует любое из указанных расширений.

Теперь, если имя файла не подходит под это выражение, тройной оператор возвращает часть после двоеточия, "$_" - в которой находится просто исходное имя файла. Затем Perl обрабатывает имя файла, как он обычно это делает с именами файлов содержащихся в: он создаёт дескриптор файла (filehandle) и разрешает использование его содержимого в скрипте. В действительности, существует несколько способов доступа к данным после открытия файла; почитай про оператор "<>", использование дескриптора STDIN, и дескриптора ARGV (отметь похожесть и различие, Фринк!), чтобы получить представление о некоторых из множества доступных методов ввода/вывода из файла в Perl.

-- С другой стороны, если текущий элемент подходит под выражение, тройной оператор вернёт код перед двоеточием, в данном случае

"acat $_ '*' 2>/dev/null|"

Затем Perl выполнит эту команду для текущего имени файла. Синтаксис может показаться немного странным, но это то, что требует "acat" (или, более точно, утилиты архивации, которыми она пользуется), чтобы обработать файлы и игнорировать сообщения об ошибках. Отметь, что команда кончается "|", символа конвейера; то, что здесь происходит наиболее похоже на организацию конвейера в оболочке. Команда выполняется, её вывод помещается в буфер, а содержимое этого буфера становится доступным для дескриптора, который бы обычно Perl открыл для этого файла - фокус-покус, чистая магия! [3]"

-- Итак, если расписать это всё в длинной форме, вот примерно то, что я сделал:


<hr>@ARGV = 
        map {                                       # использовать блочный синтаксис для "map"
                if ( /\.(gz|tgz|zip|bz2|rar|Z)$/ ){     # ищем расширения архивов
                        "acat $_ '*' 2>/dev/null|"; # Разархивируем и выводим содержимое в конвейер
                }
                else {
                        $_;                         # иначе выводим имя файла
                }
        } @ARGV;                                    # это список, по которому надо "пройтись"

<hr>

-- Так Perl обрабатывает ввод/вывод. Как только ты передаёшь ему что-нибудь полезное через командную строку или стандартный ввод, он знает, что делать. На самом деле, - тут он строго посмотрел на Фринка, который снова выглядел сконфуженным, - я бы рекомендовал изучить "perldoc perlopentut" любому, кто хочет понять, как Perl работает с вводом и выводом. Это включает в себя файлы, конвейеры (pipes), ответвление дочерних процессов (forking), создание фильтров, работу с бинарными файлами, дупликацию дескрипторов файлов, вариант "open" с одним аргументом и ещё много разных вещей. Некоторые считают, что это наиболее важный документ, прилагаемый к Perl. Просмотреть "perldoc perlipc" для закрепления - также хорошая идея, он описывает несколько связанных вопросов, включая открытие безопасных (с низким приоритетом) конвейеров в возможно небезопасных процессах, что может быть очень важно, когда приходится торопитесь.

-- Теперь, Резолв, я полагаю, что перед вами открывается новое светлое будущее. Ваша проблема будет решена, ваш менеджмент будет удовлетворён, а Ваши пользователи будут надёжно защищены от Тех, Кто За Частоколом.Если Вы согласитесь присоединиться к нам в нашем маленьком праздновании... Я только что закончил отваривать Пятнистую Собаку и... хм, куда он ушёл? Это же замечательный английский пудинг со смородиной (Spotted Dog). Я полагаю, он хотел реализовать эти изменения как можно быстрее...


Примечания

[1] "Down, Not Across." Те, кому нужны дополнительные намёки о жестоком значении Мантры Сисадмина, поищите в архивах alt.sysadmin.recovery на <http://groups.google.com>, и всё сразу станет ясно. Если нет, значит и не предполагалось, что вы это поймёте.:) (Прим. пер. Мне удалось найти два варианта объяснения: 1) "Вниз, не поперёк" - длинная строка должна разрываться и уходить вниз, а не направо, за пределы экрана 2) "Вдоль, не поперёк" - методика вскрытия вен. Радостные они ребята. Плюс DNA совпадает с аббревиатурой для ДНК. Окончательный смысл от меня ускользает, жду комментариев от более знающих людей.)

[2] Из Жаргонария:

Устройство Регулировки Отношения Неудользователя. (Прим. пер. мой вариант перевода. В оригинале,
  LART, Luser Attitude Readjustment Tool). Классический УРОН - это полено 2x4 или крупнее, используемое
  в качестве дубинки. Место применения - сверху к голове спаммеров или прочих людей, вызывающих
  у сисадминов больше печали, чем обычно. Многолетние дебаты ведётся на alt.sysadmin.recovery 
  о том, что такое по-настоящему эффективный УРОН; у метательных дубинок, полуавтоматического оружия,
  огнемётов и тактического атомного оружия есть свои сторонники. (Прим. пер. Владеющим английским
  стоит заглянуть по адресу http://info.astrian.net/jargon/.
  Практически у всех имён в статьях этой серии есть свои значения.)


[3] См. "perldoc perlopentut" для курса обучения по открытию файлов, "магии" в @ARGV, и даже "Рассеивания заклятья Двеомера" (Dispelling the Dweomer) для тех, кто уже видел слишком много магии. :)

Об авторе

Бен -- сотрудничающий редактор Linux Gazette и член Банды ответчиков (в смысле, они отвечают на возникающие вопросы читателей. Прим. перев.).

Бен родился в Москве в 1962 г. В шесть лет заинтересовался электричеством -- продемонстрировал это, воткнув вилку в розетку и вызвав пожар. С тех пор неоднократно проваливался в технологические люки. Он начал работать с компьютерами ещё в старые, добрые времена, когда их приходилось собирать из деталей и припаивать на печатные платы, а программы должны были умещаться в 4k памяти. Он с радостью заплатил бы внушительную сумму любому психологу, способному излечить его от вызванных этим кошмаров.

Последующий опыт Бена включает создание программ практически на дюжине языков, поддержку сетей и баз данных во время приближающегося урагана, а также написание статей для публикаций в разных местах: от журналов по парусному спорту до техножурналов. Завершив недавно семилетний круиз по Атлантике/Карибскому морю под парусом, он на данный момент пришвартовался в Балтиморе, где работает техническим инструктором в Sun Microsystems.

Бен работает с Linux с 1997, и считает, что именно из-за него у Бена полностью пропал интерес к развязыванию атомной войны в разных частях северо-запада Тихого океана.


Copyright (c) 2003, Ben Okopnik. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 87 of Linux Gazette, February 2003


Вернуться на главную страницу