null

Отказываемся от Python в пользу канонических утилит: sh, perl, awk, sed, ...

Один мой замечательный коллега, Сергей Кляус, написал как-то статью о проблемах использования стандартных системных утилит и довольно кардинальном способе их решения -- переходе на Python. Безусловно, в таком подходе существует масса положительных моментов. Во-первых, скрипты становятся портируемые, а это значит, что их можно будет не только запускать на серверах, но и на своей рабочей станции с, например, Windows. Во-вторых, ряд задач действительно решается гораздо лаконичнее с помощью Python, нежели стандартными утилитами (примеры можно найти в выше упомянутой статье). И заключительный, пожалуй, наиболее существенный плюс -- уровень защищённости скриптов значительно возрастает, поскольку написать "безопасный" скрипт, который не будет ломаться от первого стихотворения в имени файла, используя стандартный набор утилит -- более трудоемкая задача.

Однако, использование Python приводит к ряду недостатков. К ним относится, например, то, что Python (даже 2.*) есть не везде (примером могут послужить многочисленные инсталляции AIX систем). Конечно же, производительность решения. Принимая во внимание реалии современного администрирования, которое в большей степени принимает форму DevOps, скрипты приобретают несколько иную семантику, превращаясь из "разовых вспомогательных" утилит в "часто используемый" набор ПО, который уже не так лоялно относится к собственной производительности.
В настоящей статья я постараюсь, во-первых, заменить примеры моего коллеги более лаконичными, понятными и, иногда, более производительными решениями; а также наглядно показать, что инструментарий, имеющийся на каждом сервере не так беден, как может показаться на первый взгляд.
Честно говоря, большая часть примеров (если не все) будут приведены на основе такого инструмента, как Practical Extraction and Report Language (сокращённо perl). Поэтому, данную статью можно отчасти рассматривать и как разоблачение мифа, что код на perl нечитаем.
Сейчас мы по порядку рассмотрим примеры С.Кляуса, но сначала объясню используемые мною ключи.

-a автоматическое разделение на поля
-w включить некоторые предупреждения
-l автоматический перенос на новую строку
-p выводить строку автоматически
-n не выводить строку автоматически
-e выражение для выполнения
-E выражение для выполнения (включены некоторые опции из features, но данный ключ работает только с более-менее современными версиями perl)

1. Разбор по полям

</etc/passwd perl -F: -anE 'say $F[0], $F[1]'

2. Аналог команды echo

say "just another perl hacker,";
print "just another perl hacker,\n";

3. cat/head/tail

</etc/passwd perl -pE1 # вывести весь файл
</etc/passwd perl -pE 'exit if $. > 10' # head
</etc/passwd perl -E 'foreach(<>){next if $c++ < $.-10 ;print}' # tail
</etc/passwd perl -E '@f=<>;print for @f[$#f-9..$#f]' # другой tail

Кстати говоря, Сергей отмечает, что Python (как и perl) читает всю строку в переменную, и необходимо иметь ввиду наличие переноса строки в её последнем символе. Для избавления от этого, предлагается присвоить строке её же подстроку. В perl для этого есть функция chomp (например chomp $line). Но в рассмотренных примерах этого попросту не требуется. Зачем сначала убирать, а потом добавлять перенос на новую строку? Лишняя работа -- это не про perl.

4. grep/sed

Тут сразу хочется оговориться, что из богатого функционала sed Сергей рассмотрел лишь текстовую замену... Поэтому не буду нарушать традицию и приведу лишь её аналог в perl.

</etc/passwd perl -nE 'print if /regexp/'
</etc/passwd perl -nE 'print s/root/korg/gr'

Флаг r у оператора s назван в честь слова return и приводит к тому, что результат выржения -- измененная подстрока, а не факт замены в булевом виде.
Как видно, даже если мы захотим переписать скрипты, синтаксис сильно менять не придется. Хотя, безусловно, в случае grep будет использован другой, более богатый диалект регулярных выражений.

5. awk/cut

Ну, awk практически так и выглядит (в perl есть блоки BEGIN и END), а cut Сергей рассмотрел в контексте разделения на столбцы, а не выделения подстрок. Причем использовал он для этого регулярные выражения.
Разделение на столбцы в perl автоматизированно (см. пример 1), а вот для сравнения код на awk и perl рядышком:

awk -F: 'BEGIN{cnt=0}/Daemon/{cnt++}END{print cnt}' /etc/passwd
perl -F: -anE 'BEGIN{$cnt=0}$cnt++ if /Daemon/;END{say $cnt}' /etc/passwd

Видно, что код на perl просто несколько больше из-за синтаксических конструкций. Хотя, конечно, можно и привести пример Сергея на языке perl:

</etc/passwd perl -F: -anE '($user,undef,$uid,undef,$gecos) = split ":";
if (int($uid) < 10){say $user,$uid,$gecos}'

Или, например, так:

</etc/passwd perl -F: -anE '($user,$uid,$gecos) = (split ":")[0,2,4];
if (int($uid) < 10){say $user,$uid,$gecos}'

Впрочем, тот же эффект имеет и

</etc/passwd perl -F: -anE 'say $F[0],$F[2],$F[4] if $F[2] < 10'

6. Последним, так сказать, killerfeature Сергея был вызов внешних команд.

В качестве примера приведен некоторый аналог popen. В perl вызов "внешних команд" слегка напоминает shell. Обратные кавычки, кстати, возвращают список.

perl -E 'say `ls`'
perl -E '@lst=`ls`; print $lst[2]'

Резюме

1. Столь мало изученный, но всюду доступный инструмент perl заслуживает определенную роль в написании вспомогательных утилит. По своему быстродействию, perl выигрывает у Python на типовых задачах в два-три раза. А "безопасность" (устойчивость к нештатным ситуациям) скриптов аналогична Python.
2. Использование везде и всюду любимого инструмента, пожалуй, бессмысленно. Там где можно написать просто tail, нужно писать просто tail, а не городить несколько строчек кода.
3. Программы должны выполнять только одну функцию и делать ее хорошо, а связываться между собой через простые тектовые интерфейсы -- гласит философия UNIX. Лично я, в полной мере осознавая схожесть функционала Python и perl, рассматриваю первый как "недо" pascal, а второй как язык обработки текста; хотя сам в некоторых случаях (когда не хочется прибегать к Си) использую эти инструменты.

В лучших традициях

...написания статей о цвете рукоятки молотка для забивания гвоздей, порекомендую документацию по perl. В первую очередь, это официальная документация, которая даже иногда установлена на систему и называется perldoc. Из книг, пожалуй, как и Сергей, сделаю рекомендацию в пользу книги "Язык программирования Perl" того же издательства O'Reilly.
И, в качестве примера простенького perl-скрипта, могу привести XMPP MUC бота, описанного в другой моей статье: https://github.com/tune-it/jplbot

korg

 

Коротко о себе

Работаю в компании Tune-IT, администрирую инфраструктуру компании и вычислительную сеть кафедры Вычислительной ТехникиСПбНИУ ИТМО.

Интересы: администрирование UNIX и UNIX-like систем и активного сетевого оборудования, написание shell- и perl-скриптов, изучение технологий глобальных сетей.
Люблю собирать GNU/Linux и FreeBSD, использовать тайлинговые оконные менеджеры и писать системный софт.

Ничего не найдено. n is 0