ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.


Pitstop Велосипед детский купить
 
Глава 1 Строки 

1.18. Программа: psgrep

Многие программы (в том числе ps, netstat, Is -/, find -Is и Icpdump) часто выдают большие объемы данных. Файлы журналов тоже быстро увеличиваются в размерах, что затрудняет их просмотр. Такие данные можно обработать программой-фильтром типа grep и отобрать из них лишь часть строк, однако регулярные выражения плохо согласуются со сложной логикой - достаточно взглянуть па ухищрения, па которые приходится пускаться в рецепте 6.17. В частности, нам хотелось бы иметь возможность обращаться с полноценными запросами к выводу программы или файлу журнала. Допустим, вы спрашиваете у ps: "Покажи мне все непривилегированные процессы размером больше 10Кб" или "Какие команды работают на псевдоконсолях?" Программа psgrep умеет делать все это и бесконечно большее, потому что в ней критерии отбора не являются регулярными выражениями; они состоят из полноценного кода Peri. Каждый критерий последовательно применяется к каждой строке вывода. В результате выводятся лишь те данные, которые удовлетворяют всем аргументам. Ниже приведены примеры критериев поиска и соответствующие им командные строки. o Строки со словами, заканчивающимися на sh:
% psgrep '/sh\b/'
o Процессы с именами команд, заканчивающимися на sh:
% psgrep 'command =~ /sh$/'
o Процессы с идентификатором пользователя, меньшим 10:
% psgrep 'uid < 10'
o Интерпретаторы с активными консолями:
% psgrep 'command =~ '/"-/' 'tty ne "?'"
o Процессы, запущенные на псевдоконсолях:
% psgrep 'tty =~ /"[p-t]'
o Отсоединенные непривилегированные процессы:
% psgrep 'uid && tty eq "?"'
o Большие непривилегированные процессы:
% psgrep 'size > 10 * 2**10' 'uid != О' Ниже показаны данные, полученные при последнем вызове psgrep на нашем компьютере. Как и следовало ожидать, в них попал только net sea ре и его вспомогательный процесс:
FLAGS UID PID PPID PRI NI SIZE RSS WCHAN STA TTY TIME COMMAND
0 101 9751 1 0 0 14932 9652 do.select S p1 0:25 netscape 100000 101 9752 9751 0 0 10636 812 do_select S p1 0:00 (dns helper)
В примере 1.6 приведен исходный текст программы psgrep.
Пример 1.6. psgrep
#!/usr/bin/peri -w
#psgrep - фильтрация выходных данных ps
# с компиляцией пользовательских запросов в программный код
#
use strict;
# Все поля из заголовка PS
my ©fieldnames = qw(FLAGS UID PID PPID PRI NICE SIZE RSS WCHAN STAT TTY TIME COMMAND);
# Определение формата распаковки (в примере
# жестко закодирован формат ps для Linux)
my $fmt = cut2fmt(8, 14, 20, 26, 30, 34, 41, 47, 59, 63, 67, 72);
my %fields; # Для хранения данных
die "Thanatos unless @ARGV;
usage: $0 criterion ...
Each criterion is a Peri expression involving:
@fieldnames
All criteria must be met for a line to be printed. Thanatos
# Создать синонимы для uid, size, UID, SIZE и т.д.
# Пустые скобки необходимы для создания прототипа без аргументов
for my $name (@fieldname) {
no strict 'rets';
-name = *{lc $name} = sub () { $fields{$name} };
}
my $code = "sub is_desirable { " . join(" and ", @ARGV) . " } ";
unless (eval $code.1) {
die "Error in code: $@>\n\t$code\n";
}
open (PS, "ps wwaxi |") || die "cannot fork: $!";
print scalar ; # Строка-заголовок while ( {
@fields{@fieldnames} = trim(unpack($fmt, $_));
print if is_desirable(); # Строки, удовлетворяющие критериям
}
close(PS) || die "ps failed!"; # Преобразовать позиции разреза в формат распаковки sub cut2fmt {
my(@positions) = @_;
my Stemplate = ' ';
my $lastpos = 1;
foreach $place(positions) {
$template .= "A" . ($place - $lastpos) . " ";
$lastpos = $place;
}
$template .= "A*";
return $template;
}
suu irim {
my @out = @_;
for (Oout) {
s/"\s+//;
s/\s+$//;
} return wantarray ? Oout : $out[0];
}
# Следующий шаблон использовался для определения позиций разреза.
# Далее следует пример входных данных
й-123456789012345678901234567890123456789012345678901234567890123456789012345
#
1

2
3

4

5 6

7

# Позиции

# 8
14
20
26 30
34
41
47
59
63
67
72

Я I

|
I I
|
I
|
I
|
|
|

END

FLAGS
UID
PID
PPID
PRI
NI
SIZE
RSS
WCHAN
STA
TTY
TIME
COMMAND
100
0
1
0
0
0
760
432
doselect
S
?
0:02
init
140
0
187
1
0
0
784
452
doselect
S
?
0:02
syslogd
100100
101
428
1
0
0
1436
944
doexit
S
1
0:00
/bin/

login
100140
99 30217
402
0
0
1552
1008
posixlock
S
7
0:00
httpd
0
101
593
428
0
0
1780
1260
copythread
S
1
0:00
-tcsh
100000
101 30639
9562
17
0
924
496

R
Р1
0:00
ps axl
0
101
25145
9563
0
0
2964
2360
idetaperea
S
Р2
0:06
trn
100100
0 10116
9564
0
0
1412
928
setupframe
Т
РЗ
0:00
ssh -C

WWW
100100
0 26560
26554
0
0
1076
572
setupframe
т
Р2
0:00
less
100000
101 19058
9562
0
0
1396
900
setupframe
т
Р1
0:02
nvi /

Imp/a

В программе psgrep объединены многие приемы, представленные в книге. Об удалении начальных и конечных пропусков рассказано в рецепте 1.14. Преобразование позиций разреза в формат unpack для извлечения полей с фиксированным положением рассматривается в рецепте 1.1. Поиску регулярных выражений в строках посвящена вся глава 6. Многострочный текст, передаваемый die, представляет собой встроенный документ (см. рецепты 1.10 и 1.11). Присваивание @fields{@fieldnames} заносит сразу несколько величин в хэш %fields. Хэши рассматриваются в рецептах 4.7 и 5.10. Входные данные программы-примера, расположенные под __END__, описаны в рецепте 7.6. На стадии разработки для тестирования использовались "консервированные" данные, полученные через файловый манипулятор DATA. Когда программа заработала, мы перевели ее на получение данных из присоединенной команды ps, однако исходные данные были оставлены для будущего переноса на другие платформы и сопровождения. Конвейерный запуск других программ рассматривается в главе 16 "Управление процессами и межпроцессные взаимодействия", особенно в рецептах 16.10 и 16.13. Настоящая сила и выразительность psgrep обусловлены тем, что в Peri строковые аргументы могут представлять собой не просто строки, а программный код Peri. Похожий прием использован в рецепте 9.9, за исключением того, что is psgrep аргументы пользователя "упакованы" в процедуру is_desirable. При этом компиляция строк в код Peri выполняется всего один раз - еще перед запуском той программы, чей вывод мы обрабатываем. Например, при запросе UID ниже 10 будет сгенерирована следующая строка: eval "sub is_desirable { uid < 10 } " . 1; Загадочное . 1 в конце присутствует для того, чтобы при компиляции пользовательского кода команда eval возвращала истинное значение. В этом случае нам даже не придется проверять $@ на предмет ошибок компиляции, как это делается в рецепте 10.12. Использование произвольного кода Peri в фильтрах для отбора записей - невероятно мощная возможность, но она не является абсолютно оригинальной. Peri многим обязан языку программирования awk, который часто применялся для подобной фильтрации. Один из недостатков awk заключался в том, что он не мог легко интерпретировать входные данные в виде полей фиксированной длины (вместо полей, разделенных особыми символами). Другой недостаток - отсутствие мнемонических имен полей; в awk использовались имена $1, $2 и т. д. К тому же Peri может делать многое такое, на что не способен awk. Пользовательские критерии даже не обязаны быть простыми выражениями. Например, следующий вызов инициализирует переменную $id номером пользователя nobody и затем использует ее в выражении: % psgrep 'no strict "vars"; BEGIN { $id = getpwnamC'nobody") } uid == $id Но как использовать эти слова, uid, command и size, даже не снабжая их символом $ для представления соответствующих полей входных записей? Мы напрямую манипулируем с таблицей символов, присваивая замыкания (closures) неявным тип-глобам (typeglobs), которые создают функции с соответствующими именами. Замыкания описаны в рецепте 11.4, а их присвоение тип-глобам для создания синонимов функций - в рецепте 10.14. Однако в psgrep встречается нюанс, отсутствующий в этих рецептах, - речь идет о пустых скобках в замыкании. Благодаря скобкам функция может использоваться в выражениях везде, где допускается отдельная величина (например, строка или числовая константа). В результате создается пустой прототип, а функция обращения к полю (например, uid) вызывается без аргументов, по аналогии со встроенной функцией time. Если не создать для функций пустые прототипы, выражения "uid < 10" или "size / 2 > rss" приведут в замешательство синтаксический анализатор - он увидит в них незаконченный глоб (wildcard glob) или шаблон поиска. Прототипы рассматриваются в рецепте 10.11. Показанная версия psgrep получает входные данные от команды ps в формате Red Hat Linux. Чтобы перенести ее в другую систему, посмотрите, в каких столбцах начинаются заголовки. Такой подход не ограничивается спецификой ps или системы UNIX. Это общая методика фильтрации входных записей с использованием выражений Peri, которая легко адаптируется для другой структуры записи. Поля могут быть выстроены в столбцы, разделены запятыми или заключены в скобки. После небольшого изменения в функциях отбора программа даже подойдет для работы с пользовательской базой данных. Если у вас имеется массив записей (см. рецепт 11.9), пользователь может указать произвольный критерий отбора:
sub id() { $_->{ID} }
sub title() { $_->{TITLE} }
sub executive { title ='/(?: vice-)?president/i } # Критерии отбора указываются при вызове дгер @slowburners = дгер { id < 10 && !executive } ©employees; По причинам, связанным с безопасностью и быстродействием, такой подход редко встречается в реальных механизмах, описанных в главе 14 "Базы данных". В частности, он не поддерживается в SQL, но имея в своем распоряжении Peri и некоторую долю изобретательности, нетрудно создать свой собственный вариант. Подобная методика использована в поисковой системе http://mox. perl.com/ cgi-bin/MxScreen, но вместо получения данных от ps записи представляют собой хэши Peri, загружаемые из базы данных.


© copyright 2000 Soft group
v


?????? ???????????