Изучаем Перл, часть 1

  Автор: © Ben Okopnik
Перевод: © Павел Ступин (Кобальт)


 

Не важно, как долго вы пользуетесь Линукс - наверняка вы уже наслышены о Перле; даже возможно, что вы запускали огромное количество скриптов, при этом не подозревая об этом. Программы типа inews, mirror, debconf, majordomo, sirc и многие другие написаны на Перле и только на Перле. Если вы пользуетесь дистрибутивом Debian, "натравите" zgrep на файл Packages.gz - окажется, что 382 пакета зависят от Перла (это означает, что основная часть пакета написана на Перле), и для работы 28 других пакетов рекомендуется иметь Перл.

 

Для чего Перл хорош?

Перл великолепен в обработке текста, а также для интегрирования в единое целое разных вещей. Ведь для языка сценариев (скриптов) - все эти разные вещи являются по сути одним и тем же.
--John Ousterhout, создатель языка сценариев Tcl.

Перл (Perl) является аббревиатурой от "Язык для извлечения данных и составления отчетов" (Practical Extract and Report Language). Да. Это звучит скучно. Однако есть предположение, что если вам нужно в чем-то убедить что-нибудь типа $Некая_серьезная_организация, то Перл - это именно то, что надо. Larry Wall , автор Перла, в документации трактует название своего детища как "До патологии эклектичный обработчик чуши" (Pathologically Eclectic Rubbish Lister). И добавляет: "Только не говорите никому, что это я вам такое рассказал". Кхе-кхе...Ладно, Ларри. Из меня не вытянут ни слова.

Перл часто называют "иллюзией полноценного языка программирования", "говором швейцарских наемников в Unix" и одаривают другими...хм...комплиментами. На Перле пишутся программы из одной строки, быстро работающие приложения, огромные проекты (система контроля Amazone.com, управление содержанием сайта Netscape и система доставок Netcape, управление проектными группами в Human Genome Project и др.), а также огромное количество быстрых программ, которые выполняют широкий спектр задач. Перл вполне может эмулировать большое количество традиционных Unix-утилит (полезный совет: если вам нужно выучить awk, sed, grep и tr, я бы вам посоветовал лучше выучить один Перл. Выбрав Перл, вы получите всю функциональность перечисленных инструментов, превосходство в скорости и неичерпаемые возможности для совершенствования...Да, знал бы все это я раньше...).

Как и все современные языки программирования, Перл является объектно-ориентированным. Также возможно сетевое программирование (например, программирвоание сокетов). Программы на Перле легко портируются (хорошо написанный скрипт будет работать на Linux, BSD, Solaris, DOS, Win9x, NT, MacOS, OS/2, AmigaOS, VMS и других платформах без необходимости модификации исходного кода). Программы быстры в отладке, так как не требуют компиляции - вы просто изменяет код и запускаете скрипт. Существует огросное количество дополнительных модулей (реализации стандартных решений), которые позволят выполнять любую задачу. Также есть Comprehensive Perl Archive Network (CPAN) - лучшее о чем может мечтать Perl-программист.

 

Да. Впечатляет. Но в чем суть Перла?

Хороший вопрос. Надеюсь, что примерно через год после начала программирования на Перле вы сами сможете дать мне ответ на этот вопрос. Описание чего бы то ни было - это всегда помещение объекта в определенные рамки...закрытие его в своеобразном понятийном ящике...Я до сих пор пытаюсь найти такой, куда Перл поместился бы полностью (хорошо бы еще найти такой с надежным замком).

 

Что не следует писать на Перле?

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

Также заметьте, что сам Перл написан отнюдь не на Перле, равно как и ядро Линукс. Давайте оставим низкоуровневое программирование C/C++ и Assembler'у. Кредом каждого программиста должна быть фраза: "Определенные инструменты для определенных задач".

 

Последнее предупреждение перед стартом.

Если вы уже немного знакомы с Перлом и видите, что мой способ изложения и решения отличаются от уже выученных вами, просто замомните девиз Перла: "Существует более одного способа для решения проблемы" (There's More Than One Way To Do It или TMTOWDI [читается как 'tim-today']). В этом суть философии Перла. Разумеется, исправление очевидных ошибок в моем тексте только приветствуется.

Те из вас, кто читал мою предыдущую серию статей, посвященных программированию Shell, помнят, что скрипт начинается с так называемой "hash-bang" (знак решетки # и восклицательный знак !) или "shebang" строки:

#! /bin/bash

Это нужно для того, чтобы shell породил суб-shell, где будет выполняться ваш код. То же самое нужно и для Перла:

#! /usr/bin/perl

Строка может варьироваться в зависимости от того, где у вас расположен интерпретатор Перл.

Запомните требования, которые должны выполняться hash-bang строкой:

  1. Она должна быть первой в скрипте
  2. Решетка # должна быть первым символм на строке. Пробелы между # и ! не допускаются.
  3. Нужно указывать полный путь, а не только имя запускаемого файла.

Ну что ж. Давайте попробуем написать наш первый скрипт на Перле:

#!/usr/bin/perl
# "goodbye" - современная и ультра-депрессивная замена "Hello World"

print "Прощай, жестокий мир!\n";
unlink $0;

Ну...Скажем так, по крайне мере, программа прощается с нами перед тем как уйти в мир иной. Мисс Хорошие-манеры гордилась бы нами. Итак, что же мы сделали? Несколько очевидных вещей: сначала "#!"-строка, потом комментарий с описанием программы (еще одна штука из программирования на Shell); это, между прочем, отличная идея вставлять комментарии (запомните: слишком много комментариев не бывает!). Затем, мы выводим сообщение используя функцию print. Обратите внимание на \n в конце строки - Перл не обеспечивает автоматический перевод строки, поэтому вам предоставляется выбор - делать ли этот перевод или нет. Также заметьте ";" в конце выражения: как и в C - это обязательно, и горе тому программисту, который забудет про это. На самом деле, проверка на ошибки реализована в Перле очень даже хорошо, с относительно понятными сообщениями. Единственная проблема может быть в том, что так как символ ";" является разделителем выражений, то в случае если вы забудете написать ";", то в сообщении об ошибке будет указана не та строка, где совершена ошибка, а следующая. Разумеется, это не проблема, если вы знаете этот фокус. Но еще лучше будет просто не забывать ставить ";".

Последняя строка - это то, что совершает великое злодеяние, то есть удаляет файл скрипта. "$0" - это просто ссылка на имя исполняющегося скрипта, а "unlink" делает по сути то же самое, что и 'rm'. Заметьте, что "$0" намного полезней, чем просто "goodbye" или даже "./goodbye" - в независимости от того, как назван файл, "$0" возвращает его имя.

 

О, кстати...Немного о том, как писать код.

Я лично далек от совершенства в написании кода: раньше я часто писал такие программы, которые пишутся и больше не читаются, так как их невозможно понять. Но я постоянно совершенствуюсь и стараюсь исправиться.

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

@boats = ("Aloa", "Cheoy Lee", "Pearson", "Mason", "Swan", "Westsail", "S2", "Petersen", "Hereshoff"); # Список лодок

Таким образом мы осуществили процесс наполнения массива '@boats' названиями лодок. Неплохо, но омжно сделать то же самое, но в более гуманной форме:

@array = ("Aloa",	# French OSTAR/IORboat
	  "Cheoy Lee",	# Comfortable but expensive
	  "Pearson",	# Strong but rather heavy
	  ...
	  	);

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

 

Переменные.

В Перле все подчиняется принципу простоты использования. Перл - это так называемый "либеральный" язык, где, например, вы не сможете, определить переменную как ту, которая может принимать исключительно значения в пределах массива 32-битных положительных чисел с плавающей запятой.

В Перле существует 3 типа переменных: скаляр, массив и хэш. Несмотря на эти страшные названия, все на самом деле достаточно просто: это просто переменные, которые хранят данные, используя разную структуру.

переменные типа "скаляр" - числа, строки или ссылки

    Такие переменные обозначаются символом "$", например $num, $joe, $pointer. Примеры переменных: "0.0421", "Joe's glove", адрес в памяти "0xA000"

переменные типа "массив" - последовательно нумерованные списки скаляров

    Обозначается символом "@" (@v, @list, @variable). Например:
    0 - "Sunday"
    1 - "Monday"
    2 - "Tuesday"
    3 - "Wednesday"
    ...
    

переменные типа "хэш" - индексированные списки скаляров

    Хэши обозначаются символом "%" (%people, %x, %this_is_a_hash). Например:
    resident	-	"Sherlock Holmes"
    addr		-	"221B Baker Street"
    code		-	"NW1"
    city		-	"London"
    country		-	"GB"
    job		-	"sleuth"
    ...
    

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

Используя эти три типа переменных, вы сможете хранить любые данные (и обращаться к ним) - причем все это просто.

Еще одно важное замечание: $a, @a и %a не связаны друг с другом никаким образом. Каждой из этих переменных выделяется свое адресное пространство в памяти. В своих программах я стараюсь не использовать внешне похожие имена, такие как эти, особенно потому что существует что-нибудь типа $a[0] (ссылка на первый элемент массива @a). Вы должны знать о таких вещах.

Принимая во внимание то, что переменные могут содержать в себе данные разных типов (числа и строки), для операций с этими переменными нужны разные операторы

Оператор		Числа	Строки
---------------------------------------
Равно			==	eq
Не равно		!=	ne
Меньше			<	lt
Больше			>	gt
Меньше или равно	<=	le
Больше или равно	>=	ge

Чтобы запомнить, пользуйтесь правилом: сравнивая буквы (строки), используем буквы.

Так как я люблю давать конкретные примеры, вот вам рецепт как поседеть и получить нервный срыв:

#!/usr/bin/perl
# Скрипт проверки политической ситуации в стране

$a = "Al";
$b = "George";

if ($a > $b) { print "$a - вот это наш президент.\n";}
if ($a < $b) { print "$b - вот это наш президент.\n";}
if ($a == $b) { print "$a или $b - не имеет никакой разницы...\n";}

Гм...Программа говорит, что нет никакой разницы. Это, конечно, может отражать политическую ситуацию в стране, но как на счет наших сравнений?...да-да. Конечно. Нам нужно было использовать строковые операторы сравнения.

#!/usr/bin/perl
# Скрипт проверки политической ситуации в стране

$a = "Al";
$b = "George";

if ($a gt $b) { print "$a - вот это наш президент.\n";}
if ($a lt $b) { print "$b - вот это наш президент.\n";}
if ($a eq $b) { print "$a или $b - не имеет никакой разницы...\n";}

Вот теперь операторы сравнения работают как нужно (ага, а политическая логика отдыхает...но я начинаю уходить от темы).

Кстати, почему в первом примере Перл решил, что "Al" и "George" - это одно и тоже? С каких это пор программы стали разбираться в политике?

Причина, на самом деле, важна, так как речь идет о том, как Перл различает "истина" (true) и "ложь" (false). Учитывая, что всевозможные проверки - "if", "while", "until" и др. завиcят от этого принципа различения, нам важно понять его.

  • "0" - это всегда "ложь" (в независимости от того, является ли значение переменной строкой или числом)
  • Все неопределенные переменные (те, которым не присвоено никакое значение) - "ложь".
  • Пустые строки - "" или '' - "ложь".
  • Все остальное - "истина".

А теперь попробуйте разобраться с этими ребятами - истина или ложь?

"00"	"-1"	" "	"5 - 5"

Ответ - в конце статьи.

Другим важным моментом является интерполяция переменных, то принцип, по которому определяется интерпретировать или нет выражение, заключенное в кавычки. Например:

$name = 'Bessie';
print	'Нашу корову зовут $name.';

Оп-с. Что мы получили?

Нашу корову зовут $name.

Лично мне не кажется, что корова, которая действительно уважает себя, отозвалась на такое имя - $name (Я даже не говорю о том, как тяжело было бы произносить такое имя). Так как же нам все-таки сделать так, чтобы корова отозвалась?

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

$name = 'Bessie';
print	"Нашу корову зовут $name.";

Все! Теперь корова - наша! (те из вас, кто подумал, что-то нехорошее - немеджленно прекращайте). И все благодаря Перлу. Я же говорил, что с Перлом вы сможете делать все.

А что, если бы мы захотели вывести имя переменной? Нет проблем. В Перле это решается просто:


$joe = "Joe"
print  "Переменной \$joe присвоено значение $joe.";

Можно вывести любой метасимвол (то есть любой, зарезервированный в Перле), если перед ними ставить обратную наклонную черту ("\"). Взгляните на это:

$joe = "Joe";
print  "Переменной \"\$joe\" присвоено значение \"$joe.\"";


TMTOWDI:

print 'Переменной "$joe" присвоено значение "', $joe, '".';

Выбирайте, что больше по душе. Главное, понять разницу. Обратите внимание на то, что разные значения в выражении "print" разделяются запятой, если бы запятой не было, то выражение приобрело совершенно другое значение, но об этом в следующий раз.

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

#! /usr/bin/perl -w

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

 

Заключение.

В это раз мы совершили небольшую прогулку в мир программирования на Перле. В следующем месяце, мы зайдем немного подальше. Возможно, нам предстоить исследовать массивы и хэши...или в первый раз окунуться в океан умопомрачительных возможностей "регулярных выражений" Перла (regexes или regular expressions). Мой совет - попробуйте на деле то, что мы с вами изучили, поэкспериментируйте - по своему опыту я знаю, что это лучший способ изучения языка - экспериментировать до тех пор, пока не будет достигнут предел возможностей при ваших сегодняшних знаниях, а затем позвать на помощь кого-нибудь, кто знает больше. Запомните, вы никогда не получите хороших ответов, если не будете знать вопросов.

Удачи в экспериментах с Перлом!

 

Ben Okopnik

perl -we '$@="\145\143\150\157\040\042\112\165\163\164\040\141\156".
"\157\164\150\145\162\040\120\145\162\154\040\110\141\143\153\145\162".
"\042\040\076\040\057\144\145\166\057\164\164\171";`$@`'

 

Ответ на вопрос: Все равны "истина". Ни одно из выражений не удовлетворяет требованиям "ложных" значений. "00" - это не "0", как и "-1". Пробел " " - это не пустая строка "", а "5 - 5", если это выражение не приравнено к чему-нибудь, то оно не равно 0.

 

Ссылки: "Perl. The Complete Reference", Martin C. Brown

 

Man-страницы:

perl 	 - 	обзор
perltoc  - 	содержание документации
perlsyn	 -	синтакс 
perlrun	 -	исполнение
perltrap -	ловушки для непредупрежденных
perlfaq	 -	часто задаваемые вопросы	
perldata -	структуры данных
perlop   -	операторы и порядок действий
perlfunc -	встроенные функции
perstyle - 	стиль программирования

"perldoc" и "perldoc -f"

 


Copyright © 2000, Ben Okopnik.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 61 of Linux Gazette, January 2001

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