| Содержание | Предисловие | В

468x60comp.hardware.ani.


Приложение А

    В этой главе:


Ответы к упражнениям

В этом приложении даны ответы к упражнениям, помещенным в конце каждой главы.

Глава 2 "Скалярные данные"

1. Вот один из способов решения этой задачи:

$pi = 3.141592654;

$result = 2 * $pi * 12.5;

print "radius 12,5 is circumference $result\n";

Сначала мы присваиваем константу (число к) скалярной переменной $pi. Затем мы вычисляем длину окружности, используя значени

2. Вот один из способов решения этой задачи:

print "What is the radius: ";

chomp($radius = <STDIN>) ;

$pi = 3.141592654;

$result = 2 * $pi * $radius;

print "radius $radius is circumference $result\n";

Это похоже на предыдущий пример, но здесь мы попросили пользователя, выполняющего программу (применив для выдачи приглашения оператор print),

Если бы мы забыли применить функцию chomp, то получили бы посреди выведенной строки символ новой строки. Важно как можно быстрее в

3. Вот один из способов решения этой задачи:

print "First number: "; chomp($a = <STDIN>) ;

print "Second number: "; chomp($b = <STDIN>) ;

$c = $a * $b; print "Answer is $c.\n";

Первая строка делает три вещи: приглашает вас ввести число, считывает строку со стандартного ввода, а затем избавляется от неизбежного символа новой строки. Поскольку мы используем значение $а

Вторая строка делает то же самое со вторым числом и помещает его в скалярную переменную $Ь.

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

print "String: "; = <STDIN>;

print "Number of times: "; chomp($b = <STDIN>) ;

$c = $a x $b; print "The result is:\n$c";

Как в предыдущем упражнении, первые две строки запрашивают значения двух переменных и принимают их. Однако здесь мы не выбрасываем символ новой строки, потому что он нам нужен! Третья строка по

Глава 3 "Массивы и списочные данные"

1. Вот один из способов решения этой задачи:

print "Enter the list of strings:\n";

@list = <STDIN>;

Sreverselist = reverse @list;

print @reverselist;

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

Последние три строки можно объединить:

print "Enter the list of strings:\n";

print reverse <STDIN>;

Этот код работает аналогично предыдущему, так как операция print ожидает ввода списка, а операция reverse

2. Вот один из способов решения этой задачи:

print "Enter the line number: "; chomp($a = <STDIN>) ;

print "Enter the lines, end with "D:\n"; @b = <STDIN>;

print "Answer: $b[$a-l]";

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

Если вы попробуете запустить эту программу с терминала, конфигурированного самым обычным образом, вам нужно будет нажать клавиши [Ctrl+D], чтобы обозначить конец файла.

<

3. Вот один из способов решения этой задачи:

srand;

print "List of strings: "; @b = <STDIN>;

print "Answer: $b[rand (@b)]";

Первая строка запускает генератор случайных чисел. Вторая строка считывает группу строк. Третья строка выбирает случайный элемент из этой группы и выводит его на экран.

Глава 4 "Управляющие структуры"

1. Вот один из способов решения этой задачи:

print "What temperature is it? ";

chomp($temperature °° <STDIN>);

if ($temperature > 72) {

print "Too hot!\n";

} else (

print "Too cold!\n";

>

Первая строка приглашает ввести температуру. Вторая строка принимает введенное значение температуры. Оператор if в последних пяти

2. Вот один из способов решения этой задачи:

print "What temperature is it? ";

chomp($temperature = <STDIN>) ;

if ($temperature > 75) (

print "Too hot!\n";

} elsif ($temperature < 68) (

print "Too cold!\n";

) else {

print "Just right!\n";

1

Здесь мы модифицировали программу, введя трехвариантный выбор. Сначала температура сравнивается со значением 75, затем со значение

3. Вот один из способов решения этой задачи:

print "Enter a number (999 to quit): ";

chomp($n = <STDIN>) ;

while ($n != 999) f

$sum += $n;

print "Enter another number (999 to quit): ";

chomp($n = <STDIN>);

1 print "the sum is $sum\n";

Первая строка приглашает ввести первое число. Вторая строка считывает это число с терминала. Цикл while продолжает выполняться до

Операция += накапливает числа в переменной $sum. Обратите внимание:начальное значение этой переменной — undef, что очень хорошо для сумматора, потому что первое прибавляемое значение будет фактически прибавляться к нулю (помните, что при ис

В этом цикле мы должны запрашивать и принимать еще одно число, чтобы проверка в начале цикла производилась по вновь введенному числу.

После выхода из цикла программа выводит накопленные результаты.

Если сразу же ввести 999, то значение переменной $sum будет равно не нулю, а пустой строке

4. Вот один из способов решения этой задачи:

print "Enter some strings, end with "D:\n";

@strings = <STDIN>;

while (Ostrings) (

print pop @strings;

}

Сначала программа запрашивает строки. Эти строки сохраняются в переменной-массиве @strings (по одной на элемент).

Управляющее выражение цикла while — Sstrings. Это управляющее выражение ищет только одно значение ("истина" или "ложь"), поэтому вычисляет выражение в скалярном контексте. И

Тело цикла выводит значение, полученное путем "выталкивания" крайнего справа элемента массива. Следовательно, поскольку этот элемент выводится, при каждом выполнении цикла массив становится на один элемент короче.

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

5. Вот один из способов решения этой задачи без использования списка:

for ($number = 0; $number <= 32; $number++) {

$square = $number * $number;

printf "%5g %8g\n", $number, $square;

}

А вот как можно решить задачу с помощью списка:

foreach $number (0..32) (

$square = $number * $number;

printf "%5g %8g\n", $number, $square;

}

В обоих решениях применяются циклы с использованием операторов for и foreach.

В первом решении использован традиционный С-подобный оператор for. Первое выражение устанавливает переменную $

Во втором решении использован оператор foreach, подобный аналогичному оператору C-shell. С помощью конструктор

Глава 5 "Хеши"

1. Вот один из способов решения этой задачи:

%map = qwfred apple green leaves blue ocean);

print "A string please: "; chomp($some_string = <STDIN>);

print "The value for $some_string is $map($some_string(\n";

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

Этот хеш можно создать и с помощью серии отдельных операций присваивания:

$map('red') = 'apple';

$map('green'( = 'leaves';

$map('blue'} = 'осеап',-

2. Вот один из способов решения этой задачи:

chomp(Swords = <STDIN>); # читать слова минус символы новой строки foreach $word (@words) (

$count{$word} = $count($word} + 1; # или $count{$word}++ t foreach $word (keys %count) {

print "$word was seen $count($word) times\n";

}

Первая строка считывает строки в массив @ words. Вспомните: в результате выполнения этой операции каждая строка становится отдельн

В следующих четырех строках осуществляется обход массива, при этом $word приравнивается по очереди каждой строке. Функция chompДругой распространенный способ задания этой операции инкременти-рования приведен в комментарии. Опытные Perl-программисты обычно отличаются леностью (мы называем это "краткостью") и никогда не пишут одну и ту же ссылку на хеш в обеих ча

После подсчета слов в последних нескольких строках программы осуществляется просмотр хеша и поочередное получение всех его ключей. После вычисления строкового значения сам ключ и соответствующее ему значение выводятся на экран.

Есть и другое решение, отличающееся от описанного только тем, что перед словом keys в третьей с конца строке вставлена операция sort.

Глава 6 "Базовые средства ввода-вывода^

1. Вот один из способов решения этой задачи:

print reverse о;

Вас, может быть, удивит краткость этого ответа, но он, тем не менее, верен. Вот как работает этот механизм:

а) Сначала функция reverse ищет список своих аргументов. Это значит, что операция "ромб" (О) выполняется в списочном контексте. Следовательно, все строки файлов, указанных к

б) Затем функция reverse меняет порядок следования элементов списка на обратный.

в) Наконец, функция print получает список-результат и выводит его. И. Вот один из способов решения этой задачи:

print "List of strings:\n";

chomp(@strings = <STDIN>) ;

foreach (@strings) (

printf "%20s\n", $_;

)

Первая строка приглашает ввести список строк.

Следующая строка считывает все строки в один массив и избавляется от символов новой строки.

В цикле foreach осуществляется проход по этому массиву с присвоением переменной $_ значения каждой строки.

Функция printf получает два аргумента. Первый аргумент определяет формат "%20s\n", который означает 20-символь

3. Вот один из способов решения этой задачи:

print "Field width: ";

chomp($width = <STDIN>) ;

print "List of strings:\n";

chomp(@strings = <STDIN>);

foreach (@strings) (

printf "%$(width}s\n", $_;

}

В решение, данное к предыдущей задаче, мы добавили приглашение ввести ширину поля и ответ на него.

Есть еще одно изменение: строка формата printf теперь содержит ссылку на переменную. Значение переменной $width

printf "%$widths\n", $_; #WRONG

потому что тогда Perl искал бы переменную с именем $ widths, а не п

printf "%$width"."s\n", $_; * RIGHT

потому что символ конца строки завершает также имя переменной, защищая следующий символ от присоединения к имени.

Глава 7 "Регулярные выражения"

1. Вот несколько возможных ответов:

а) /а+ь*/

б) /\\*\**/ (Вспомним, что обратная косая черта отменяет значение следующего за ней специального символа.)

в) / ($whatever) {3} / (Не забудьте про круглые скобки, иначе множитель будет действовать только на последний символ $whatever;г) /[\000-\377] (5}/ или /(. |\п) (5)/ (Использ

д) / (л l \s) (\s+) (\s+\2)+ (\s | $) / (\s — это не пробельный символ, а \2 —<

2. а) Вот один из способов решения этой задачи:

while (<STDIN>) {

if (/a/i && /e/i &S /i/i &S /o/i && /u/i) ( print;

)

Здесь у нас приведено выражение, состоящее из пяти операций сопоставления. Все эти операции проверяют содержимое переменной $_, ку

Обратите внимание: если любая из пяти гласных не обнаруживается, остальная часть выражения пропускается, потому что операция && не вычисляет свой правый аргумент, ес

б) Еще один способ:

while (<STDIN>) (

if (/a.*e.*i.*o.*u/i) ( print;

} )

Этот ответ, как оказывается, проще. Здесь у нас в операторе if используется более простое регулярное выражение, которое ищет пять

в) Вот один из способов решения этой задачи:

while “STDIN” (

if (/"[eiou]*a[лiou]*e[лaou]*i[^ae

> )

Выглядит уродливо, но работает. Чтобы написать такое, просто подумайте: "Что может стоять между началом строки и первой буквой а?", а затем "Что может стоять между первой буквой а и первой букв

3. Вот один из способов решения этой задачи:

while (<STDIN>) {

chomp;

($user, $gcos) = (split /:/)[0,4];

($real) = split (/,/, $gcos) ;

print "$user is $real\n";

}

Во внешнем цикле while производится считывание по одной строке из файла паролей в переменную $_.Вторая строка тела цикла while означает разбиение строки на отдельные переменные с использованием в качестве разделителя двоеточия. Два из этих семи значений заносятся в отд

Поле GCOS (пятое поле) затем разбивается на части с использованием в качестве разделителя символа запятой, и список-результат присваивается Оператор print затем выводит результаты на экран.

4. Вот один из способов решения этой задачи:

while (<STDIM>) (

chomp;

($gcos) = (split /:/)[4];

($real) =split(/,/, $gcos);

($first) ° split(/\s+/, $real);

$seen($first>++;

} foreach (keys %seen) (

if ($seen($_) > 1) {

print "$_ was seen $seen($_) times\n";

) }

Цикл while работает во многом так же, как цикл while из предыдущего

В цикле foreach осуществляется проход по всем ключам хеша %seen (именам из файла паролей) с присваиванием кажд

5. Вот один из способов решения этой задачи:

while (<STDIN>) (

chomp;

($user, $gcos) = (split /:/)[0,4];

($real) = split /,/, $gcos;

($first) = split (/\s+/, $real);

$seen($first) .= " $user";

}

foreach (keys %names) (

$this == $names{$_);

if ($this =~ /. /) {

print "$_ is used by:?this\n";

} }

Эта программа похожа на ответ к предыдущему упражнению, но вместо того чтобы просто подсчитывать, сколько раз у нас встречалось определенное имя, мы присоединяем регистрационное имя пользовател

В цикле foreach, как и в ответе к предыдущему упражнению, осуществляется проход по полученному в результате хешу, но вместо того, чтобы проверять, больше ли единицы значение

Глава 8 "Функции"

1. Вот один из способов решения этой задачи:

sub card {

my %card_map;

@card_map(l..9} = qw (

one two three four five six seven eight nine );

my($num) = @_;

if ($card_map($num}) {

return $card_map($num};

) else (

return $num;

) } # driver routine:

while (0) {

chomp;

print "card of $_ is ", &card($ ), "\n";

)

Подпрограмма scard (названная так потому, что она возвращает название на английском языке для данного числа) начинается с инициали

С помощью оператора if мы определяем, принадлежит ли значение заданному диапазону, отыскивая это число в хеше: если в хеше имеется соответствующий элемент, проверка дает зна

$card map($num) || $num;

Если значение слева от | | истинно, то этозначение всего выражения, которое затем и возвращается. Если оно ложно (например, ког

Подпрограмма-драйвер последовательно получает строки, отсекает символы новой строки и передает их по одной в программу &card,

2. Вот один из способов решения этой задачи:

sub card ( ...; } # из предыдущего ответа print "Enter first number: ";

chomp($first = <STDIN>) ;

print "Enter second number: "; , chomp($second = <STDIN>) ;

$message = card($first) . " plus " .

card($second) . " equals " .

card($first+$second) . ".\n";

print "\u$message";

Первые два оператора print приглашают ввести два числа, а операторы, следующие сразу же за ними, считывают эти значения в

Затем путем троекратного вызова &card — по одному разу для каждого значения и один раз для суммы

После формирования сообщения его первый символ с помощью операции \и переводится в верхний регистр. Затем сообщение выводится на экран.

3. Вот один из способов решения этой задачи:

sub card f

my %card_map;

@card_map(0..9} = qw (

zero one two three four five six seven eight nine );

my($num) = @_;

my($negative) ;

if ($num < 0) {

$negative = "negative ";

$num = - $num;

) if ($card_map($num)) (

return $negative . $card_map($num};

} else (

return $negative . $num;

)

Здесь мы объявили массив %card_map, чтобы обнулять его значения.

Первый оператор if инвертирует знак переменной $num и присваивает переменной $negativeВторой оператор if определяет, находится ли значение переменной $num (теперь положительное) в хеше. Если да, т

Последний оператор if можно заменить выражением:

$negative . ($card_map{$num) || $num) ;

Глава 9 "Разнообразные управляющие структуры Вот один из способов решения этой задачи:

sub card (} # из предыдущего упражнения

while О ( ## НОВОЕ ##

print "Enter first number: ";

chomp($first = <STDIN>) ;

last if $first eq "end"; ## НОВОЕ ##

print "Enter second number: ";

chomp($second = <STDIN>) ;

last if $second eq "end"; ## НОВОЕ ##

$message = Scard ($first) . " plus " .

card($second) . " equals " .

card($first+$second) . ".\n";

print "\u$message";

} ## НОВОЕ ##

Обратите внимание на появление цикла while и двух операций last. Вот так-то!

Глава 10 "Дескрипторы файлов и проверка файлов

1. Вот один из способов решения этой задачи:

print "What file? ";

chomp($filename = <STDIN>);

open(THATFILE, "$filename") ||

die "cannot open Sfilename: $!";

while (<THATFILE>) (

print "$filename: $_"; # предполагается, что $ заканчивается \п }

В первых двух строках дается приглашение ввести имя файла, который затем открывается с дескриптором т hat file. Содержимое этого ф

2. Вот один из способов решения этой задачи:

print "Input file name: ";

chomp($infilename = <STDIN>);

print "Output file name: ";

chomp($outfilename = <STDIN>);

print "Search string: ";

chomp($search = <STDIN>);

print "Replacement string: ";

chomp($replace = <STDIN>);

open(IN,$infilename) II

die "cannot open $infilename for reading: $!";

## необязательная проверка существования файла

## $outfilename

die "will not overwrite $outfilename" if -e $outfilename;

open (OUT,"$outfilename") ||

die "cannot create $outfilename: $!";

while (<IN>) { # читать строку из файла IN в $_

s/$search/$replace/g; # change the lines

print OUT $_; # вывести эту строку в файл OUT ) close (IN);

close (OUT) ;

Эта программа основана на программе копирования файлов, описанной выше в этой главе. К новым особенностям здесь относятся приглашение вводить строки и команда подстановки в середине циклаОбратите внимание на то, что обратные ссылки в регулярном выражении работают, а вот обращение к памяти в заменяющей строке нет.

3. Вот один из способов решения этой задачи:

while (о) (

chomp; t удалить символ новой строки

print "$_ is readable\n" if -r;

print "$_ is writable\n" if -w;

print "$_ is executable\n" if -x;

print "$_ does not exist\n" unless -e;

}

При каждом выполнении цикла while читается имя файла. После удаления символа новой строки файл проверяется (с помощью остальных оп

4. Вот один из способов решения этой задачи:

while (<>) (

chomp;

$аде = -М;

if ($oldest_age < $аде) ( $oldest_name = $_;

$oldest_age = $аде;

} > print "The oldest file is $oldest_name ",

"and is $oldest age days old.\n";

Сначала мы выполняем цикл для каждого считываемого имени файла. Символ новой строки отбрасывается, а затем с помощью операции -м вычисляется возраст файла в днях. Если возраст превышает возраст

По завершении цикла оператор print выдает отчет.

Глава 11 "Форматы"

1. Вот один из способов решения этой задачи:

open(PW,"/etc/passwd") II die "How did you get logged in?";

while (<PW>) (

($user,$uid,$gcos) = (split /:/)[0,2,4];

($real) ° split /,/,$gcos;

write;

(

format STDOUT =

@“<““ @>””> @“““““““““““““““

$user, $uid, $real

Первая строка открывает файл паролей. В цикле while этот файл обрабатывается построчно. Для того чтобы можно было загрузить скаляр

Формат дескриптора файла stdout определяет простую строку с тремя полями. Их значения берутся из трех скалярных переменных, значения которым присваиваются в цикле2. Вот один из способов решения этой задачи:

# прибавить к программе из первой задачи... format STDOOT_TOP = Username User ID Real Name

Все, что нужно для добавления к предыдущей программе заголовков страниц,— это добавить формат начала страницы. Указанным выражением мы помещаем заголовки в столбцы.

Чтобы выровнять столбцы, мы скопировали текст формата stdout и, используя в нашем текстовом редакторе режим замены, заменили поля @<“ линиями ====.Это можно сделать благо

3. Вот один из способов решения этой задачи:

# прибавить к программе из первой задачи.. . format STDOUT_TOP = Page @<“ $%

Username User ID Real Name

Здесь для получения заголовков страниц мы опять-таки ввели формат начала страницы. Этот формат содержит также ссылку на переменную $%,

Глава 12 "Доступ к каталогам"

1. Вот один из способов решения этой задачи:

print "Where to? ";

chomp($newdir = <STDIN>) ;

chdir($newdir) II die "Cannot chdir to $newdir: $!";

foreach (<*>) { print "$_\n";

}

В первых двух строках запрашивается и считывается имя каталога.

С помощью третьей строки мы пытаемся перейти в каталог с указанным именем. В случае неудачи программа аварийно завершается.

В цикле foreach осуществляется проход по списку. Но что это за список? Это развертывание в списочном контексте, в результате которого мы получим список всех имен файлов, сов

2. Вот один из способов решения этой задачи с помощью дескриптора каталога:

print "Where to? ";

chomp ($newdir = <STDIN>) ;

chdir($newdir) ||

die "Cannot chdir to $newdir: $!";

opendir(DOT,".") |I

die "Cannot opendir . (serious dainbramage): $!";

foreach (sort readdir(DOT)) { print "$_\n";

) closedir(DOT) ;

Так же, как в предыдущей программе, мы запрашиваем новый каталог. Перейдя в него посредством команды chdir, мы открываем каталог,

А вот как сделать это с помощью развертывания:

print "Where to? ";

chomp($newdir = <STDIN>) ;

chdir($newdir) || die "Cannot chdir to $newdir: $!";

foreach (sort <* .*>) ( print "$_\n";

)

Да, это, по сути дела, еще одна программа из предыдущего упражнения, но мы вставили перед операцией развертывания операцию sort и

Глава 13 "Манипулирование файлами и каталогами Вот один из способов решения этой задачи:

unlink @ARGV;

Да, именно так. Массив @argv — это список имен, подлежащих удалению. Операция unlinkКонечно, здесь не реализован ни механизм уведомления об ошибках, ни опции -f и -i, ни другие подобные вещи, но

2. Вот один из способов решения этой задачи:

($old, $new) ” @ARGV; # назвать их

if (-d $new) ( # новое имя каталог, его нужно откорректировать ($basename = $old) =~

# каталога $old $new .= "/$basename"; # и добавить его к новому имени > rename($old,$new) [| die "Cannot rename $old to $new: $!";

Рабочая лошадка в этой программе последняя строка, но все остальное тоже нужно на тот случай, если новое имя принадлежит каталогу.

Сначала мы даем наглядные имена двум элементам массива oargv. Затем, если имя $new — каталог, нам нужно откорр

Наконец, после добавления собственно имени каталога мы завершаем задачу вызовом rename.

3. Вот один из способов решения этой задачи:

($old, $new) = 3ARGV; # назвать их

if (-d $new) ( # новое имя каталог, его нужно откорректировать ($basename = $old) =~ s#.*

# каталога $old $new .= "/$basenaroe"; # и добавить его к новому имени } link($old,$new) || die "Cannot link $old to $new: $!";

Эта программа идентична предыдущей программе за исключением самой последней строки, потому что мы создаем ссылку, а не выполняем переименование.

4. Вот один из способов решения этой задачи:

if ($ARGV[0] eq "-s") ( # нужна символическая ссылка ;

$symlink++; # запомнить shift(@ARGV); # и отбросить флаг -s

> • • ! • .. , . ' .' . ($old, $new) = @ARGV; * назвать их

if (-d $new) ( # новое имя — каталог, его нужно откорректировать

($basename = $old) =~ s#.*/##s; # получить название собственно # каталога $old

$new .= "/$basename"; # и добавить его к новому имени > if ($symlink) ( # wants a symlink

symlink($old,$new) ;

) else ( # нужна жесткая ссылка

link($old,$new); , )

Средняя часть этой программы такая же, как в предыдущих двух упражнениях. Новые здесьВ первых строках осуществляется проверка первого аргумента программы. Если этот аргумент равен -s, то скалярная переменная $ symlink

shift(@ARGV) ;

мы могли бы написать

shift;

Последние несколько строк проверяют значение $symlink. Оно будет равно либо 1, Вот один из способов решения этой задачи:

foreach $f (<*>) {

print "$f -> $where\n" if defined($where =• readlink($f));

}

Скалярной переменной $f присваивается по очереди каждое из имен файлов текущего каталога. Для каждого имени переменнойпроверке if, a print пропускается. Если же операция readlink возвращает какое-то значение, то

Глава 14 "Управление процессами"

1. Вот один из способов решения этой задачи:

if ('date' =~ /"S/) (

print "Go play!\n";

} else (

print "Get to work!\n";

}

Оказывается, команда date выводит букву s в качестве первого символ

2. Вот один из способов решения этой задачи:

open(PW,"/etc/passwd") ;

while (<PW>) {

chomp;

($user,$gcos) = (split /:/)[0,4];

($real) = split (/,/, $gcos); '

$real($user) = $real;

)• close(PW);

open(WHO,"who I") || die "cannot open who pipe";

while (<WHO>) (

($login, $rest) =/" (\S+) \s+(.*)/;

$login = $real($login) if $real($login);

printf "%-30s ts\n",$login,$rest;

}

В первом цикле создается хеш %real, ключи которого регистрационны

Во втором цикле осуществляется просмотр результата выполнения команды who, которая вызвана при помощи дескриптора файла. Каждая строка полученного в результате выраже

Операции открытия дескриптора файла и начала цикла можно заменить строкой

foreach $_ ('who') (

с тем же результатом. Единственное различие состоит в том, что вариант программы с использованием дескриптора файла может приступить к работе, как только who

3. Вот один из способов решения этой задачи:

open(PW,"/etc/passwd");

while (<PW>) (

chomp;

($user,$gcos) = (split /:/)[0,4];

($real) = split(/,/, $gcos);

$real($user} •= $real;

} close(PW) ;

open(LPR,"1Ipr") I I die "cannot open LPR pipe";

open (WHO,"who]") || die "cannot open who pipe";

while (<WHO>) {

# или заменить предыдущие две строки на foreach $_ ('who') (

($login, $rest) = /л (\S+) \s+(.*)/;

$login = $real($loginl if $real($login} ;

printf LPR "%-30s %s\n",$login,$rest;

}

Разница между этой программой и программой из предыдущего упражнения состоит в том, что мы добавили дескриптор файла lpr, открытый

4. Вот один из способов решения этой задачи:

sub mkdir f

'system "/bin/mkdir", @_;

}

Здесь команда mkdir получает аргументы прямо из аргументов подпрограммы. Однако возвращаемое значение должно подвергнуться

5. Вот один из способов решения этой задачи:

sub mkdir (

my($dir, $mode) = 8_;

('system "/bin/mkdir", $dir) && chmod($mode, $dir) ;

1

Сначала мы описываем локальные аргументы этой подпрограммы — $dir и $ mode.

Глава 15 "Другие операции преобразования данных Вот один из способов решения этой задачи:

while (о) { chomp;

$slash = rindex ($_,"/");

if ($slash > -1) (

$head = substr($_,0,$slash);

$tail = substr($_,$slash+l);

} else (

($head,$tail) = ("", $_) ;

) print "head = '$head', tail = '$tail'\n";

>

Каждая строка, прочитанная операцией "ромб", сначала пропускается через операцию chomp, которая удаляет символ новой строки. Затем

2. Вот один из способов решения данной задачи:

chomp(@nums = <STDIM>); # обратите внимание на особый случай

# использования chomp @nuros = sort ( <=> $b } @nums;

foreach (@nums) (

printf "%30g\n", $_;

}

В первой строке в массив @nums вводятся все числа. Во второй строке этот массив сортируется в числовом порядке, для чего используе

3. Вот один из способов решения этой задачи:

open(PW,"/etc/passwd") || die "How did you get logged in?";

while “PW” (

chomp;

($user, $gcos) = (split /:/)[0,4];

($real) = split!/,/, $gcos) ;

$real($user} = $real;

($last) = (split /\s+/, $real)[-l];

$last{$user} = "\L$last";

} close(PW) ;

for (sort by_last keys %last) (

printf "%30s %8s\n", $real($_}, $_;

>

sub by_last ( ($last($a} cmp $last($b}) || ($a cmp $b). }

В первом цикле создается хеш %last, ключи которого регистрационны

Во втором цикле выводится %геа1, упорядоченный по значениям %iast. Это делается с использованием определения сортировки, предоставленного подпрограммой b

4. Вот один из способов решения этой задачи:

while (<>) (

substr($_,0,I) =~ tr/a-z/A-Z/;

substr($_,!) — tr/A-Z/a-z/;

print;

1

Для каждой строки, прочитанной операцией "ромб", мы используем две операции tr — по одной для разных частей строки. Первая

Вот другое решение, с использованием только строковых операций с двойными кавычками:

while (О) {

print "\u\L$_";

}

Если вы самостоятельно нашли это решение, поставьте себе дополнительно пять баллов.

Глава 16 "Доступ к системным базам данных Вот один из способов решения этой задачи:

while (@pw == getpwent) {

($user, $gid, $gcos) - @pw(0,3,6);

($real) = split /,/, $gcos;

$real($user) = $real;

$members($gid} .= " $user";

($last) = (split /\s+/, $real)(-l);

51ast($user) " "\L$last";

)

while (@gr - getgrent) (

($gnarae, $gid, $meinbers) = @gr[ 0,2,3);

$rnembers( $gid) .=“ " $merabers";

$gname($gid) - $gname;

)

for $gid (sort by_gname keys %gname) (

tall = ();

for (split (/\s+/, $members($gidl)) ( $all{$_)++ if length $_;

1

Omembers = () ;

foreach (sort by_last keys %all) (

push(@members, "$real($_} ($_)");

}

$meinberlist = join(", ", @members);

write;

)

sub by_gname ( $gname($al cmp $gname($bl; ) sub by_last ( ($last(a) cmp $last($b)) || ($a cmp $b); )

format STDOUT = @<<<< @<<<< A<<<<<<<<<<<<<<<<<<<

$gname($gid), "($gid)", $memberlist

^<<<<<<<<<<<<<<<<<<<

$memberlist

Да, в этом не так просто разобраться, но вам это придется сделать самостоятельно, чтобы проверить усвоенные знания.

Глава 17 "Работа с пользовательскими базами данных"

1. Вот один из способов решения этой задачи:

dbmopen(%ALIAS, "/etc/aliases", undef) II

die "No aliases!: $!";

while (($key,$value) - each(tALIAS)) (

chop($key,$value) ;

print "$key $value\n";

1

Первая строка открывает DBM псевдонимов. (В вашей системе DBM псевд

2. Вот один из способов решения этой задачи:

# program 1:

dbmopen(%WORDS,"words",0644) ;

while (О) {

foreach $word (split(/\W+/)) ( $WORDS($word)++;

> } dbmclose(%WORDS) ;

Первая программа (записывающая) открывает DBM words в текущем каталоге, создавая файлы words, dir

# program 2:

dbmopen(%WORDS,"words",undef) ;

foreach $word (sort { SWORDS)$b} <=> SWORDS($a[ } keys %WORDS) ( print "Sword SWORDS(Sword)\n";

1 dbmclose(%WORDS) ;

Вторая программа также открывает DBM words в текущем каталоге. Сложная на первый взгляд строка foreach<

Глава 18 "Преобразование других программ в Вот один из способов решения этой задачи:

for (;;) (

($user,$home) = (getpwent)[0,7];

last unless $user;

next unless open(N,"$home/.newsrc");

next unless -M N < 30; ## added value :-) while (<N>) f

if (/^comp\ . lang\ .perl\ .announce: /) { print "$user is a good person, ", "and reads comp.lang.peri.announce!\n");

last;

} } }

Самый внешний цикл это цикл for, который выполняется "вечно";выход из этого цикла осуществляется посредством операции last, стоящей внутри него. При каждом выполнении цикла операция getpwent Если значение $user пусто, осуществляется выход из цикла for. Следующие две строки ищут последний файл<

В цикле while осуществляется чтение по одной строке из файла .newsrc.

while.

Глава 19 "CG1-программирование"

1. Вот один из способов решения этой задачи:

use strict;

use CGI qw (:standard);

print header(), start_html("Add Me"It-print hi("Add Me") ;

if (paramO) {

my $nl = param('fieldl');

my $n2 = param('field2');

my $n3 = $n2 + $nl;

print p("$nl + $n2 = <strong>$n3</strong>\n") ;

} else (

print hr(), start_form();

print pC'First Number:", textfield("fieldl"));

print p("Second Number:", textfield("field2"));

print p(submit("add"), reset ("clear"));

print end_form(), hr () ;

} print end_html();

Если входных данных нет, то просто создается форма с двумя текстовыми полями (при помощи метода textfield). При наличии входной ин

2. Вот один из способов решения этой задачи:

use strict;

use CGI qw(:standard);

print header(), start_html("Browser Detective");

print hi("Browser Detective"), hr();

my $browser = $ENV('HTTP_USER_AGENT'};

$_ '" $browser;

BROWSER:(

if (/msie/i) (

msie($_) ;

) elsif (/mozilla/i) (

netscape($_) ;

) elsif (/lynx/i) (

lynx($_);

1 else (

default($_) ;

> >

print end_html() ;

sub msie)

print pC'Internet Explorer: @_. Good Choice\n") ;

}

sub netscape (

print pC'Netscape: @_. Good Choice\n") ;

t

sub lynx {

print p("Lynx: @_. Shudder...");

(

sub default (

print pC'What the heck is a @_?");

}

Главный момент здесь проверка переменной среды HTTP_USER_ AGENT н




|     Назад     |  

| Содержание | Предисловие | В



Сайт создан в системе uCoz