Анимация
JavaScript


Главная  Библионтека 

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

16.7. Чтение содержимого STDERR 569

Решение

Воспользуйтесь числовым синтаксисом перенаправления и дублирования для файловых дескрипторов. Для упрощения примеров мы не проверяем возвращаемое значение open, но вы обязательно должны делать это в своих программах! Одновременное сохранение STDERR и STDOUT:

Soutput = cmd 2>&1; # Для ...

# или

Spid = ореп(РН, "cmd 2>&1 "), # Для open while (<РН>) { } # Чтение

Сохранение STDOUT с игнорированием STDERR:

Soutput = cmd 2>/dev/null , й Для ...

й или

Spid = ореп(РН, "cmd 2>/dev/null Г); й Для open while (<РН>) { } # Чтение

Сохранение STDERR с игнорированием STDOUT:

Soutput = cmd 2>&1 1>/dev/null; # Для

# или

Spid = open(PH, "cmd 2>&1 1>/dev/null 1"), # Для open while (<PH>) { } # Чтение

Замена STDOUT и STDERR команды, то есть сохранение STDERR и направление STDOUT в старый STDERR:

Soutput = cmd 3>&1 1>&2 2>&3 3>&--; # Для

й или

Spid = ореп(РН, "cmd 3>&1 1>&2 2>&3 3>&-"); # Для open while (<РН>) { } # Чтение

Чтобы организовать раздельное чтение STDOUT и STDERR команды, проще и надежнее всего будет перенаправить их в разные файлы, а затем прочитать из этих файлов после заверщения команды:

system("prog args 1>/tmp/program.stdout 2>/tmp/program.stderr");

Комментарий

При выполнении команды оператором ... , сцепленным вызовом open или system для одной строки Perl проверяет наличие символов, имеющих особый смысл для командного интерпретатора. Это позволяет перенаправить файловые дескрипторы новой программы. STDIN соответствует файловому дескриптору с номером О, STDOUT - 1, а STDERR - 2. Например, конструкция 2>файл перенаправляет STDERR в файл. Для перенаправления в файловый дескриптор используется специальная конструкция &N, где N - номер файлового дескриптора. Следовательно, 2>&1 направляет STDERR в STDOUT.

Ниже приведена таблица некоторых интересных перенаправлений файловых дескрипторов.



570 Глава 16 • Управление процессами и межпроцессные взаимодействия Перенаправление Значение

0</dev/null

Немедленно выдать EOF в STDIN

1>/dev/null

Игнорировать STDOUT

2>/dev/null

Игнорировать STDERR

2>&1

Направить STDERR в STDOUT

2>8,-

Закрыть STDERR (не рекомендуется)

3<>/dev/tty

Связать файловый дескриптор 3 с /dev/tty в режиме

чтения/записи

На основании этой таблицы мы рассмотрим самый сложный вариант перенаправления в решении;

Soutput = cmd 3>&1 1>&2 2>&3 3>&-;

Он состоит из четырех этапов.

Этап 1: 3>&1

Скопировать файловый дескриптор 1 в новый дескриптор 3. Прежнее место назначения STDOUT сохраняется в только что открытом дескрипторе.

Этап 2: 1>&2

Направить STDOUT по месту назначения STDERR. В дескрипторе 3 остается прежнее значение STDOUT.

Этап 3: 2>&3

Скопировать файловый дескриптор 3 в дескриптор 2. Данные STDERR будут поступать туда, куда раньше поступали данные STDOUT.

Этап 4: 3>&-

Перемещение потоков закончено, и мы закрываем временный файловый дескриптор. Это позволяет избежать «утечки» дескрипторов.

Если подобные цепочки сбивают вас с толку, взгляните на них как на обычные неременные и операторы присваивания. Пусть неременная $fd1 соответствует STDOUT, а $fd2 - STDERR. Чтобы поменять значения двух неременных, понадобится временная неременная для хранения промежуточного значения. Фактически происходит следующее:

$fd3 = $fd1, $fd1 = $fd2; $fd2 = $fd3, $fd3 = undef;

Когда все будет сказано и сделано, возвращаемая оператором . . . строка будет соответствовать STDERR выполняемой команды, а STDOUT будет направлен в прежний STDERR.

Во всех примерах важна последовательность выполнения. Это связано с тем, что командный интерпретатор обрабатывает перенаправления файловых дескрипторов слева направо.

systemCprog args 1>tnipfile 2>&1); systemCprog args 2>&1 1>tmpfile);



16.8. Управление потоками ввода и вывода другой программы 571

Первая команда направляет и STDOUT и STDERR во временный файл. Вторая команда направляет в файл только STDOUT, а STDERR будет выводиться там, где раньше выводился STDOUT. Непонятно? Снова рассмотрим аналогию с переменными и присваиваниями. Фрагмент

# system ("prog args 1>tmpfile 2>&1 ),

$fd1 = "tmpfile"; # Сначала изменить место назначения STDOUT

$fd2 = $fd1; # Направить туда же STDERR

сильно отличается от другого фрагмента:

# system("prog args 2>&1 1>tmpfile);

$fd2 = $fd1; # Совместить STDERR со STDOUT

$fd1 = "tmpfile": # Изменить место назначения STDOUT

l> Смотри также-

Дополнительные сведения о перенаправлении файловых дескрипторов приведены в странице руководства s/z(l) вашей системы (если есть). Функция system описана в perlfunc{ 1).

16.8. Управление потоками ввода и вывода другой программы

Проблема

Вы хотите управлять как входными, так и выходными данными другой программы. Функция open позволяет решить одну из этих задач, но не обе сразу.

Решение

Воспользуйтесь стандартным модулем 1РС::0реп2:

use IPC::0реп2;

open2(.README, .WRITEME, Sprogram); print WRITEME "heres your input\n; Soutput = <README>; close(WRITEME); close(README);

Комментарий

Желание управлять вводом и выводом другой программы возникает очень часто, однако за ним таится на удивление много опасностей. Поэтому вам не удастся вызвать open в виде:

open(DOUBLE HANDLE, " программа аргументы 1") # НЕВЕРНО

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



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