Глава 14: Управление процессами.
14.1 Использование функций system и ехес
Когда вы из командной строки shell задаете выполнение какой-либо команды, он обычно создает новый процесс. Этот новый процесс становится порожденным процессом shell, выполняется независимо, но в координации с последним.
Аналогичным образом Perl-программа в состоянии запускать новые процессы и может делать это, как и большинство других операций, несколькими способами.
Самий простой способ запуска нового процесса — использовать для этого функцию system. В простейшей форме эта функция передает в совершенно новый shell /bin/sh одну строку, которая будет выполняться как команда. По выполнении команды функция system возвращает код завершення данной команды (если все было нормально — это, как правило, 0). Вот пример того, как Perl-программа выполняет команду date c помощью shell*:
system("date");
Здесь мы не проверяем возвращаемое значение, но неудачный исход выполнения команд н date вряд ли возможен.
Куда идет результат этой команды? Откуда поступают исходные данные, если они нужны команде? Хорошие вопросы, и ответы на них позволят узнать, чем отличаются различные способы создания процессов.
* В данном случае shell фактически не используется, поскольку Рсгі сам выполняет операций shell, если командная строка достаточно проста, как в данном случае.
Три стандартних файла для функции system (стандартный ввод, стандартный вывод и стандартный вывод ошибок) наследуются от Perl-процесса. Таким образом, результат выполнения команды date в приведенном выше примере направляется туда же, куда поступает результат выполнения функции print stdout — скорее всего, на дисплей визвавшего ее пользователя. Поскольку ви запускаете shell, то можете переадресовать стандартный вывод, пользуясь обычными для /bin/sh операциями переадресации. Например, чтобы направить результаты работы команды date в файл right_now, нужно сделать что-то вроде этого:
system("date >right_now") && die "cannot create right_now";
На этот раз ми не только посилаем результат команды date в файл, внполняя переадресацию в shell, но и проверяем статус возврата. Если статус возврата — значение "истина" (не нуль), это значит, что с командой shell что-то произошло, и функция die внполнит свою миссию. Данное правило обратно обичним правилам выполнения операций в Perl: ненулевое возвра-щаемое значение операций system, как правило, указивает на какую-то ошибку.
Аргументом функции system может быть все, что пригодно для передачи в /bin/sh, поэтому можно задавать сразу несколько команд, разделяя их точками с запятой или символами новой строки. Процесси, после которих указан символ &, запускаются, но программа не ждет их завершення, т.е. в данном случае все происходит аналогично тому, как если бы вы ввели в shell строку, которая заканчивается символом &.
Вот пример задания команд date и who в shell с передачей результатов в файл, заданний Perl-переменной. Все это выполняется в фоновом режиме, чтобы для продолжения выполнения Perl-сценария не нужно было ждать завершення данного процесса.
$where = "who_out.".++$і; # получить новое имя файла system "(date; who) >$where &";
В этом случае функция system возвращает код выхода shell и показывает таким образом, успешно ли был запущен фоновый процесс, но не сообщает, были ли успешно выполнены команды date и who. В этой заключенной в двойные кавички строке производится интерполяция переменних, поэтому переменная $where заменяется своим значением (это делает Perl, а не shell). Если бы вы хотели обратиться к переменной shell с именем $where, вам нужно било би поставить перед знаком доллара обратную косую или использовать строку в одинарних кавычках.
Помимо стандартних дескрипторов файлов, порожденний процесс наследует от родительского процесса много других вещей. Это текущее значение, заданное командой umask, текущий каталог и, конечно, идентификатор пользователя.
Кроме того, порожденний процесс наследует все переменнне среды. Эти переменные обычно изменяются командой csh setenv или же соответствующим присваиванием и командой export shell (/bin/sh). Переменные среды используются многими утилитами, включая сам shell, для изменения порядка работы этих утилит и управления ими.
В Perl предусмотрена возможность проверки и изменения текущих переменных среды посредством специального хеша, который называется %env. Каждый ключ этого хеша соответствует имени переменной среды, а соответствующее значение — значенню переменной. Содержимое данного хеша отражает параметры среды, переданные Perl родительским shell; изменение хеша изменяет параметри среды, которую использует Perl и порожденные им процессы, но не среды, используемой родительскими процессами.
Вот простая программа, которая работает, как printenv:
foreach $key (sort keys %ENV) {
print "$key = $ENV($key)\n";
}
Обратите внимание: знак равенства здесь — это не символ операции присваивания, а просто текстовый символ, с помощью которого функция print выдает сообщения вида TERM=xterm или USER=merlyn.
Вот фрагмент программы, с помощью которого значение переменной path изменяется таким образом, чтобы поиск команды grep, запущенной функцией system, производился только в "обычных" местах:
$oldPATH = $ENV{ "PATH"); # сохранить предыдущий путь
$ENV("PATH") = "/bin:/usr/bin:/usr/lib"; # ввести известньй путь
system("grep fred bedrock >output") ; # запустить команду
$ENV("PATH") = $oldPATH; # восстановить предыдущий путь
Как много текста придется набирать! Гораздо быстрее будет просто установить локальнее значение для этого элемента хеша.
Несмотря на наличие некоторых недостатков, операция local может делать одну вещь, которая не под силу операции ту: она способна присваивать временное значение одному элементу массива или хеша.
{
local $ENV ("PATH"> " "/bin:/usr/bin:/usr/lib";
system("grep fred bedrock >output");
}
Функция system может принимать не один аргумент, а список аргументов. В этом случае Perl не передает список аргументов в shell, а рассматривает первый аргумент как подлежащую выполнению команду (при необходимости производится ее поиск согласно переменной path), а остальные аргументы — как аргументи команды без обычной для shell интерпретации. Другими словами, вам не нужно заключать в кавычки пробельные символы и беспокоиться об аргументах, которые содержат угловые скобки, потому что все это — просто символы, передаваемые в программу. Таким образом, следующие две команды зквивалентны:
system "grep 'fred flintstone' buffaloes"; # с использованием shell
system "grep","fred flintstone","buffaloes"; # без использования shell
Применение в функции system списка, а не одной строки, зкономит также один процесс shell, поэтому поступайте так при любой возможности. (Если форма функции system c одним аргументом достаточно проста, Perl сам оптимизирует код, полностью убирая вызов shell и обращаясь к соответствующей программе непосредственно, как если бы вы использовали вызов функции с несколькими аргументами.)
Вот еще один пример зквивалентных форм:
$cfiles = ("fred.c","barney.c"); # что компилировать
$options = ("-DHARD","-DGRANITE"); # опции
system "cc -o slate $options $cfiles"; # c shell
system "cc","-o","slate",$options,$cfiles"; # без shell
Назад | Вперед
Содержание (общее) | Содержание раздела
Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:
|