Анимация
JavaScript
|
Главная Библионтека Комментарий Создать выходной фильтр несложно - достаточно открыть STDOUT разветвляющим вызовом open, а затем позволить порожденному процессу фильтровать STDIN в STDOUT и внести те изменения, которые он посчитает нужным. Обратите внимание: выходной фильтр устанавливается до генерации выходных данных. Это вполне логично - нельзя отфильтровать вывод, который уже покинул ващу программу. Все подобные фильтры должны устанавливаться в порядке очередности стека - последний установленный фильтр работает первым. Рассмотрим пример, в котором используются два выходных фильтра. Первый фильтр нумерует строки; второй - снабжает их символами цитирования (как в сообщениях электронной почты). Для файла /etc/motd результат выглядит примерно так; > Welcome to Linux, version 2.0.33 on a 1686 > > "The software required Windows 95 or better, > so I Installed Linux." Если изменить порядок установки фильтров, вы получите следующий результат; Welcome to Linux, Kernel version 2.0.33 on a 1686 > 1 > 2 > 3 > 4 "The software required Windows 95 or better, so I Installed Linux." Исходный текст программы приведен в примере 16.1. Пример 16.1. qnumcat #1 /usr/bin/perl й qnumcat - установка сцепленных выходных фильтров numberO; # Установить для STDOUT нумерующий фильтр quoteO; # Установить для STDOUT цитирующий фильтр while (о) { # Имитировать /bin/cat print; close STDOUT; й Вежливо сообщить потомкам о завершении exit, sub number { die "cannot fork: $!" unless defined $pid; while (<STOIN>) { print; last unless --$lines ; exit; 16.6. Предварительная обработка ввода 567 ту $pid; return If $pid = open(STDOUT, "-), die "cannot fork- $i" unless defined $pid; while (<STOIN>) { printf "%d- %s", $ , $ 1 exit; sub quote { my $pid; return if $pid = open(STDOUT, "-); die "cannot fork; $!" unless defined $pid, while (<STDIN>) { print "> $ } exit; Как и при любых разветвлениях, для миллиона процессов такое решение не подойдет, но для пары (или даже нескольких десятков) процессов расходы будут небольшими. Если ваша система изначально проектировалась как многозадачная (как UNIX), все обойдется дешевле, чем можно себе представить. Благодаря виртуальной памяти и копированию во время записи такие операции выполняются достаточно эффективно. Разветвление обеспечивает элегантное и недорогое решение многих (если не всех) задач, связанных с многозадачностью. > Смотри также- Описание функции open в perlfunc(l); рецепт 16.4. 16.6. Предварительная обработка ввода Проблема Ваша программа умеет работать лишь с обычным текстом в локальных файлах. Однако возникла необходимость работать с экзотическими файловыми форматами - например, сжатыми файлами или Web-документами, заданными в виде URL. Решение Воспользуйтесь удобными средствами Perl для работы с каналами и замените имена входных файлов каналами перед тем, как открывать их. Например, следующий фрагмент автоматически восстанавливает архивные файлы, обработанные утилитой gzip: §ARGV = map { /\.(gzZ)$/ "gzip -de $ !":$ } @ARGV, while (<>) { Й...... A чтобы получить содержимое URL перед его обработкой, воспользуйтесь программой GET из модуля LWP (см. главу 20 «Автоматизация в Web»): @ARGV = map { m#"\w+: # ? "GET $ !":$ } @ARGV; while (<>) { # ....... Конечно, вместо HTML-кода можно принять простой текст. Для этого достаточно воспользоваться другой командой (например, lynx -dump). Комментарий Как показано в рецепте 16.1, встроенная функция Perl open очень удобна: каналы открываются в Perl так же, как и обычные файлы. Если то, что вы открываете, похоже на канал, Perl открывает его как канал. Мы используем эту особенность и включаем в имя файла восстановление архива или иную предварительную обработку. Например, файл "09tails.gz" превращается в "gzcat -do OQtails, gz ". Эта методика применима и в других ситуациях. Допустим, вы хотите прочитать /etc/passwd, если компьютер не использует NIS, и вывод, ypcat passwd в противном случае. Мы определяем факт использования NIS по выходным данным программы domainname, после чего выбираем в качестве открываемого файла строку "</etc/passwd" или "ypcat passwd". Spwdinfo = domainname =~ /"(\(попе\))?$/ < /etc/passwd : ypcat passwd ; open(PWD, Spwdinfo) or die "cant open Spwdinfo: $!", Ho и это еще не все! Даже если вы не собирались встраивать подобные возможности в свою программу, Perl делает это за вас! Представьте себе фрагмент вида: print "File, please "; chomp($file = о); open (FH, $file) or die "cant open $file: $ ; Пользователь может ввести как обычное имя файла, так и строку вида "webget http: www. perl, com " - и ваша программа вдруг начинает получать выходные данные от webget! А если ввести всего один символ, дефис (-), то при открытии для чтения будет интерполирован стандартный ввод. В рецепте 7.7 эта методика использовалась для автоматизации обработки ARGV. [> Смотри также- Рецепты 7.7; 16.4. 16.7. Чтение содержимого STDERR Проблема Вы хотите выполнить программу с помощью system, . . . или open, но содержимое ее STDERR не должно выводиться в ваш STDERR. Необходимо либо игнорировать содержимое STDERR, либо сохранять его отдельно. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 [ 183 ] 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |