Журнал LinuxFormat - перейти на главную

LXF71:Perl

Материал из Linuxformat
Перейти к: навигация, поиск

Содержание

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);

Форматирование отчётов

Функция 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;

как видите, вместо файла вы можете открыть программу. Здорово, правда?

Персональные инструменты
купить
подписаться
Яндекс.Метрика