- Подписка на печатную версию:
- Подписка на электронную версию:
- Подшивки старых номеров журнала (печатные версии)
LXF71:Perl
Материал из Linuxformat.
Perl Марко Фиоретти |
---|
|
Perl Михаил Смирнов |
---|
Содержание |
Perl поток выполнения, файлы и отчёты
чАстЬ 3 Марко Фиоретти (Marco Fioretti) представляет технологии создания утончённых сценариев Perl.
При правильном подходе к программированию сценарии Perl ведут себя очень интеллектуально. они могут считывать данные с жёстких дисков, сохранять отчёт о своей деятельности в журналах (log-файлах) и выполнять код только при условии выполнения всех требований.
Возможно, вы знаете, что последнее — выполнение кода при определённых условиях — называется управлением ходом выполнения (flow control). С этой темы мы начнём сегодняшний выпуск, а затем рассмотрим операции файлового ввода-вывода, позволяющие читать и записывать данные на жёсткий диск и передавать их в другие программы.
операторы управления выполнением
Perl содержит практически все операторы управления ходом выполнения языка С, хотя некоторые из них имеют другие названия и другой синтаксис. Например, оператор if-else выглядит так, как вы и ожидаете, но при этом допускает вложения при помощи краткой команды elsif:
if (MONEY > 50) { print “Ask mum for a little extra money\n”; } elsif ((MONEY > 0) && ($MONEY <= 50)) { print “Ask mum for MORE money!\n”; } else { print “MUM! I’m in trouble!\n”; }
Вместо if можно использовать unless, имеющий прямо противоположное значение.
unless ($MONEY > 1000000) { print “Better ask mum for some money...\n”; }
оператор while выступает в двух видах:
while ($MONEY < 1000000) { print “Ask for more money...\n”; } # или (эффект тот же самый): do { print “Ask for more money...\n”; } while ($MONEY < 1000000);
Этот код не будет выполнен ни разу, если у вас уже есть миллион. Если вы хотите быть уверены, что тело цикла в фигурных скобках будет выполнено минимум один раз, напишите until.
do { print “Ask for at least Ј10 more...\n”; } until ($MONEY > 1000000);
Еще один способ создания циклов — это эквивалентные операторы for и foreach. Второй оператор обычно используется при обработке массивов и хэшей, и в этом состоит единственная разница между ними.
for ($i = 0; $i < 100; $i++) { #Сделать что-нибудь сто раз } foreach $JEDI_KNIGHT ( keys %JEDI_DIRECTORY ) { print “ The phone number of $JEDI_KNIGHT is $JEDI_DIRECTORY{$JEDI_KNIGHT}{‘Phone number’}\n”; }
Во втором случае при каждой следующей итерации цикла переменная $JEDI_KNIGHT будет принимать значение следующего элемента массива ключей. Если её опустить, то значение ключа будет присваиваться вездесущей переменной $_.
работа с файлами.
Перед тем, как начинать работать с файлом, разумно будет узнать, обладает ли он свойствами, которые нам необходимы. Perl имеет множество операторов для таких «файловых проверок». Здесь приведён только короткий обзор, весь список можно посмотреть на http://www.unix.org.ua/orelly/perl/prog3/ch03_10.htm
if (-e $FILE) # Если файл $FILE существует.... if (-r $FILE) # Если файл $FILE существует и может быть прочитан if (-d $FILE) # Если $FILE – это существующий каталог
Если все проверки пройдены, чтение и запись файлов из Perl выполняются очень просто, но вы должны использовать функции open и close для открытия и закрытия каждого файла, доступ к которому вам нужен.
open( FILE_HANDLE, name_of_file) || die “Oh my, what happened to my file!\n” ; #сделать всё что, вы хотели с этим файлом close(FILE_HANDLE)
Функция die прерывает выполнение сценария и выводит строку, переданную ей в качестве аргумента, в стандартный поток ошибок (STDERR). В первой инструкции этого примера оператор OR (двойная вертикальная черта) позволяет прервать выполнение только в том случае, если файл не может быть открыт. Вы не обязаны использовать die, но если вы забудете обработать ошибку, то рискуете попасть в число тех, кто целыми часами пытается понять, почему ничего не работает.
В первой строке функция open получает файловый дескриптор, используемый в Perl как указатель на настоящий файл, имя которого содержится во втором аргументе. он обычно начинается с символа, обозначающего в каком режиме требуется открыть файл — для чтения (символ <), для записи (>), или дописывания в конец (>>).
open(MY_FILE, “< $SOME_FILE_TO_READ”) or die(“Could not read from $SOME_FILE_TO_READ\n”); open(MY_FILE, “> /home/mylogin/some_file_to_write”) or die(“Could not write to your file\n”); open(MY_FILE, “>> $SOME_FOLDER/$SOME_FILE”) or die(“Could not append MORE data to $SOME_FOLDER/$SOME_FILE\n”);
будьте осторожны при записи: если вы открываете файл в таком режиме, всё его содержимое будет потеряно. когда вам нужно сохранить существующие данные, используйте режим дополнения (>>), как это сделано в третьей инструкции примера. Если вы забудете указать режим доступа, Perl на всякий случай откроет файл только для чтения.
При помощи скалярных переменных можно генерировать имена файлов и пути к ним на лету, как это сделано в первой и последней командах. я рекомендую всегда пользоваться этим методом. Даже если имя файла точно известно, лучше поместить его в переменную и использовать её в разных местах программы. тогда если что-то изменится, то править имя файла придётся только в одном месте.
тем временем, наш файл открыт. как нам прочитать его или что-то в него записать? Для записи можно использовать прекрасно вам известную функцию print или её аналог printf, позволяющий лучше контролировать формат вывода. Чтобы увидеть разницу, попробуйте выполнить следующий сценарий:
#! /usr/bin/perl $MIDICHLORIAN_RATE = 4533233.434; $JEDI_QUOTE = ‘The Force is strong with this one!’; open(TEST, “> testfile.txt”) || die “Cannot open testfile.txt\n”; print TEST “$MIDICHLORIAN_RATE: $JEDI_QUOTE;\n”; printf TEST “%5.2f: %20.30s;\n”, $MIDICHLORIAN_RATE,$JEDI_QUOTE; close (TEST);
Запустите этот код несколько раз, изменяя значения переменных $MIDICHLORIAN_RATE и $JEDI_QUOTE и пронаблюдайте за содержимым файла testfile.txt, чтобы посмотреть как изменяется форматирование. Нечётное число символов % в параметрах printf обозначает начало форматирования текста: %5.2f выводит $MIDICHLORIAN_RATE как десятичную дробь с двумя цифрами после запятой, вторая последовательность %20.30s делает $JEDI_QUOTE строкой минимум из 20 и максимум из 30 символов, с выравниванием вправо. Полный список команд, понимаемых printf, можно найти в документации Perl.
когда речь заходит о чтении файлов, у нас появляется две возможности — прочитать файл строчка за строчкой или же загрузить его в массив одной командой, чтобы впоследствии обработать.
# прочитать файл построчно open(TEST, “< testfile.txt”) || die “Cannot open testfile.txt\n”; while(<TEST>) { # Сейчас текущая строка файла содержится в переменной по умолчанию $_ $LINE = $_ ; #сделать что-то с $LINE; } close (TEST); # ...или сохранить всё его содержимое в массиве @ALL_THE_LINES open(TEST, “< testfile.txt”) || die “Cannot open testfile.txt\n”; @ALL_THE_LINES = <TEST>; close (TEST);
Форматирование отчётов
- Изучение Perl-измов
Синтаксис Perl может быть непонятным, но иногда он очень близок к естественному английскому языку. Например, оператор if-then обычно записывается в такой же форме, как это принято в языке C – сначала идёт условие, а потом, в фигурных скобках – команды которые нужно в этом случае выполнить. однако простые условия, включающие всего одну команду для выполнения можно записать почти так же, как английскую фразу:
print “SORRY, no more money” if ($ACCOUNT_BALANCE <= 0); print “Access Denied!\n” unless ($WHO_IS_AT_THE_DOOR eq ‘Me’);
Функция printf создана для вывода смеси из фиксированных строк и переменных, отформатированных, как вам нравится. Но её неудобно использовать при форматировании длинного многострочного текста. к счастью, Perl (как язык для генерации отчётов) имеет пару решений, предназначенных как раз для таких целей.
Представьте себе обычный сценарий для телефонной книги, который в начале своей работы читает значения переменных $NAME, $STREET_NAME_AND_NUMBER, $CITY и $POST_CODE из базы данных. Вторая часть сценария должна отобразить прочитанные значения компактным и легко читаемым способом. Первым решением является использование Perl-аналога команды оболочки here documents. Просто поместите все переменные в простой шаблон и отметьте его начало и конец каким-нибудь словом, примерно так:
print <<END_OF_RECORD; Name: $NAME Street: $STREET $CITY $POST_CODE $COUNTRY END_OF_RECORD
Этот код работает так же просто, как и выглядит. При выполнении команды print выводится весь текст вплоть до заключительного слова END_OF_RECORD, причём вместо имён переменных подставляются их значения. Единственной проблемой является невозможность выравнивания, так что строки с переменными вроде $STREET и $COUNTRY будут выровнены по-разному и текст будет выглядеть неаккуратно.
С этим можно бороться при помощи таких команд, как format и write. Первая используется для точного позиционирования переменной в строке и указания, сколько символов она может занимать. Делается это при помощи так называемых шаблонов («picture line») — сначала устанавливаются поля для переменных, а затем — список переменных, которые нужно подставлять в эти поля.
format STDOUT_RECORD = Name: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $NAME Street: @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> $STREET @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>>>>> @>>>>>>>>>>>>>> $CITY, $POST_CODE, $COUNTRY
Эта кучка иероглифов определяет шаблон под названием STDOUT_RECORD, состоящий из трёх полей — строк предназначенных для печати. разница между ними и нашим первым шаблоном в том, что здесь каждая переменная сопровождается своей инструкцией по форматированию. Например, первая строка содержит символ @, за которым следует 36 символов <. быть может, выглядит это ужасно, но смысл очень прост – в позиции @ нужно вывести не более 37 символов переменной $NAME, выключенных влево. Переменная $POST_CODE, согласно тому же синтаксису должна занять не более 7 символов, выравнивается вправо и выводится в третьей строчке всегда в одном и том же месте.
Но это – только определение шаблона. Думайте о нём, как о картонке, в которой вырезаны прямоугольники для записи значений переменных. теперь настало время воспользоваться ею по назначению.
$~ = “STDOUT_RECORD”;
write;
Говоря по-русски, тут написано: записать в стандартный поток вывода данные, следуя шаблону STDOUT_RECORD. Функция Perl format понимает много других обозначений полей для вывода переменных – # используется для определения выровненных числовых полей, а ^ задаёт внутри шаблона блок для вывода нескольких строк. Чтобы выровнять текст по центру, вместо символов < или > используется вертикальная черта |. как всегда, подробности вы можете найти в документации.
КАК отКрытЬ проГрАмму
одной из сильных сторон Unix является возможность собрать из каскада большого числа маленьких утилит одну мощную программу. Вы можете делать то же самое в сценариях Perl. Фокус состоит в использовании в аргументе функции open вертикальной черты | перед именем исполняемой программы или после неё (вместо имени файла и символа метода доступа).
# Чтение вывода программы program_1 open(README, “program_1 |”) or die “Could not open program_1\n”; # отправка ваших данных в программу program_2 open(README, “| program_2”) or die “Could not open program_2\n”;
как видите, вместо файла вы можете открыть программу. Здорово, правда?