Выпуск 18. Август 2014
← Отчет о хакатоне 19-20 июля | Содержание | Использование портов GPIO в Raspberry Pi. Часть 2 →Однострочники в Perl
Самый стандартный и часто используемый вариант написания кода на Perl — это создание текстового файла с кодом программы. Например, можно создать текстовый файл hello.pl
вот с таким содержанием:
#!/usr/bin/perl
print "Hello\n";
И можно выполнить код этой программы в консоли:
$ perl hello.pl
Hello
Но иногда бывает очень удобно не писать отдельную программу в текстовом файле, а сразу написать в консоли в одну строчку весь код, который мы хотим выполнить. Такие команды называются однострончки (по английски — oneliner). Например:
$ perl -e 'print "Hello\n"'
Hello
Ключ -e и -E
Собственно говоря, ключ -e
— это самый важный ключ для написания однострочников. Все что угодно можно сделать только с помощью этого ключа. Все остальные ключи были добавлены исключительно для упрощения написания однострочников.
Ключ -e
— это выполнить код, который находится сразу после этого ключа. Например, сложить два числа:
$ perl -e 'print 2+5 . "\n"'
7
Чтобы не писать каждый раз символ для перевода на новую строку \n
очень удобно использовать вместо оператора print
оператор say
— оператор say
сам делает переход на новую строку, а еще say
удобнее писать, так как это слово короче чем слово print
. Но для того, чтобы оператор say
можно было использовать, нужно сказать:
$ perl -e 'use feature "say"; say 2+5'
7
Если не указать use feature "say";
, то мы получим ошибку:
$ perl -e 'say 2+5'
Number found where operator expected at -e line 1, near "say 2"
(Do you need to predeclare say?)
syntax error at -e line 1, near "say 2"
Execution of -e aborted due to compilation errors.
Но писать каждый раз use feature "say";
слишком утомительно, поэтому появился новый ключ -E
. Его можно использовать вместо -e
, и он включит все новые штуки, которые есть в Perl:
$ perl -E 'say 2+5'
7
Ключ -M
Perl — замечательный язык, очень много в нем есть из коробки, но Perl очень силен тем, что у него есть куча библиотек. Например, вот однострочник, который скачивает веб-страницу, считает сколько на этой странице символов и выводит это число:
$ perl -E 'use LWP::Simple; say length get("http://ivan.bessarabov.ru")'
6096
Ключ -M
позволяет упростить подключение библиотеки к однострочнику. Вот как выглядит эта же команда с ключом -M
:
$ perl -MLWP::Simple -E 'say length get("http://ivan.bessarabov.ru")'
6096
Вот еще один пример. Хочу вывести десятый элемент последовательности Фибоначчи. Вот как выглядит однострочник без ключа -M
(модулю Math::Fibonacci
нужно ясно указывать, какие функции нужно добавить в пространство имен):
$ perl -E 'use Math::Fibonacci qw(term); say term 10'
55
А вот более простой вариант этого однострочника с ключом -M
:
$ perl -MMath::Fibonacci=term -E 'say term 10'
55
Ключ -n
Иногда хочется не просто что-то посчитать и вывести, а как-то обработать вывод других программ. И для этих целей однострочники великлепно подходят.
Например, у нас есть какая-то програма, которая создает некий вывод:
$ echo -e '1\n2\n3'
1
2
3
Мы хотим преобразовать этот вывод — возвести каждое число в квадрат. Для того, чтобы прочитать STDIN, в Perl используется бриллиантовый оператор (diamond operator) <>
:
$ echo -e '1\n2\n3'| perl -E 'while (<>) { say $_ ** 2 }'
1
4
9
Для того, чтобы упростить написание подобных однострочников, был сделан ключ -n
. При использовании этого ключа код, переданный в -E
обрамляется:
LINE:
while (<>) {
# your program goes here
}
И при использовании ключа -n
однострочник выглядит так:
$ echo -e '1\n2\n3'| perl -nE 'say $_ ** 2'
1
4
9
butterfly operator
С ключом -n
иногда используется специальный хакерский секретный оператор “бабочка” }{
Чуть изменим задачу из прошлого раздела. У нас есть скрипт, который создает вывод:
$ echo -e '1\n2\n3'
1
2
3
Нужно просумировать все числа из вывода этого скрипта.
Если бы мы решали эту задачу с помощью Perl-скрипта, то мы бы написали что-то вроде:
while (<>) {
$sum += $_;
}
say $sum;
Мы хотим решить эту задачу с помощью однострочника. Ключ -n
создает вот такой код:
LINE:
while (<>) {
# your program goes here
}
Но нам нужно выполнить команду после того, как цикл отработает. Для этого и используется “butterfly operator”. Вообще, это никакой не оператор, а просто пара фигурных скобок. Первая фигурная скобка закрывает цикл, а вторая фигурная сбобка открывет новый блок, чтобы сохранить корректный синтаксис. Код получается таким:
LINE:
while (<>) {
$sum += $_
}{
say $sum
}
А однострочник выглядит вот так:
$ echo -e '1\n2\n3'| perl -nE '$sum += $_ }{ say $sum'
6
Ключ -a
Другая задача. Нужно обработать вывод команды, которая печатает на экран данные в виде таблицы:
$ echo -e 'a\t1\nb\t2\nc\t3'
a 1
b 2
c 3
Нужно отобразить все буквы из первого столбца, у которых цисло во втором столбце нечетное. То есть, должно быть:
$ echo -e 'a\t1\nb\t2\nc\t3' | perl -E ...
a
c
Вот длинный однострочник, который решает эту задачу. Разрезаем строку по пробелам и выводим первый элемент массива, если второй элемент массива — нечетное число:
$ echo -e 'a\t1\nb\t2\nc\t3' | perl -nE 'my @e = split /\s+/, $_; say $e[0] if $e[1] % 2'
a
c
Так писать, конечно, совсем не весело. Поэтому появился ключ -a, при использовании которого строка из дефолтной переменной разрезается на отдельные элементы, которые попадают в специальный массив @F. Вот как можно решить задачу с помощью ключа -a
:
$ echo -e 'a\t1\nb\t2\nc\t3' | perl -naE 'say $F[0] if $F[1] % 2'
a
c
По дефолту -a
разрезает строку по пробелам. Но с помощью ключа -F
можно указать паттерн, по которому будет проводиться разрезание. Например. В файле /etc/passwd
разделителем ялвяется доветочие:
$ cat /etc/passwd | head -n 2
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
Вот однострочник, который находит все User ID (колонка 3 в файле /etc/passwd
), в которых есть цифра 1. Скрипт выводит логин (это колонка 1) и User ID.
$ cat /etc/passwd | perl -F: -naE 'say "$F[0] $F[2]" if $F[2] =~ /1/'
daemon 1
uucp 10
proxy 13
gnats 41
libuuid 100
syslog 101
messagebus 102
ntp 103
sshd 104
vagrant 1000
statd 105
bessarabov 1001
mysql 106
redis 107
elasticsearch 108
Ну и конечно паттерн, который передается в -F
, может быть регулярным выражением. Например, есть скрипт который разделяет буквы всякой ерундой, нужно убрать ерунду и отобразить только буквы через пробел:
$ echo -e 'a---b\nc__d\ne=====f'
a---b
c__d
e=====f
Вот простое и понятное и очень аккуратное решение:
$ echo -e 'a---b\nc__d\ne=====f' | perl -F'/[=_-]+/' -naE 'print "$F[0] $F[1]"'
a b
c d
e f
Резюме
Однострочники в Perl — это удобный способ очень быстро решить небольшую задачу. Для работы в консоли часто используют команды sed и awk. Но если человек умеет работать с Perl, то стоит использовать именно его.
В этой статье описаны самые базовые способы использования perl в консоли. Полное описание всех возможных способов запуска perl есть в документации perlrun.
← Отчет о хакатоне 19-20 июля | Содержание | Использование портов GPIO в Raspberry Pi. Часть 2 →