Выполнить внешнюю программу можно также с помощью функции system, которая организует синхронный запуск программы и возвращает код завершения. Код завершения 0 означает, что команда была выполнена успешно. Приведем пример ее использования в программе, архивирующей файлы с суффиксом .pl в текущем каталоге:
use English; # использовать длинные имена спец. переменных
# в ОС MS Windows архивируем файлы с помощью pkzip
if ($OSNAME =~ m/win/i) {
system "pkzip", "-a", "pearls.zip", "*.pl";
# в ОС GNU/Linux архивируем файлы с помощью tar и gzip
} elsif ($OSNAME =~ m/linux/i) {
system "tar -cv *.pl | gzip > pearls.tar.gz";
}
При вызове с одним строковым аргументом функция system() использует для запуска командный интерпретатор операционной системы так же, как функции exec(), open() и операция qx(). При передаче ей нескольких аргументов она запускает внешнюю программу с помощью системного вызова (обращения к операционной системе). Чтобы обеспечить успешный поиск запускаемой программы, можно добавить каталог, где находится программа, в список путей поиска. Например, таким образом:
{ # временно помещаем каталог с программой в пути поиска
local $ENV{"PATH"} = $path_to_the_program; # каталог
system($program_to_execute); # вызов программы
} # значение $ENV{"PATH"} будет восстановлено
Выполнение внешних программ можно организовать с помощью функции open, если требуется обмениваться данными с этими программами, используя перенаправление потоков ввода-вывода. Для этого функции open() вместо имени файла передается командная строка с именем выполняемой программы и ее аргументами. Если нужно передать поток данных для обработки из Perl-программы в вызываемую программу, то перед командой указывается символ командного конвейера '|'. Как это делается, видно из очень простого примера, в котором случайным образом генерируются числовые пароли, а затем они направляются для сжатия в архив программой gzip:
# открываем выходной поток, направляем его внешней программе
open my $archive, "| gzip > passwords.gz";
for (my $i = 1; $i <= 12; $i++) { # генерируем пароли
printf $archive "%06.0f\n", rand 999999;
}
close $archive; # закрываем выходной поток
Когда нужно принять выходной поток внешней программы для обработки в Perl-программе, то символ конвейера команд '|' ставится в конце командной строки:
# открываем входной поток, полученный от внешней программы
open my $archive, "gzip -d < passwords.gz |";
while (my $line = <$archive>) { # читаем пароли из архива
print $line;
}
close $archive; # закрываем выходной поток
(Используемый в примерах архиватор gzip распространяется свободно, версии для самых разных ОС доступны на сайте http://www.gzip.org.)
Иногда требуется организовать выполнение программы таким образом: вначале запускается загрузчик, который, в зависимости от условий, заданных в конфигурации программы, запускает вместо себя основную программу. Этот подход можно реализовать с помощью функции exec, которая заменяет работающую программу на указанную. Так можно запускать не только Perl-программы. Этот прием можно проиллюстрировать таким примером:
print "Выполняется загрузчик: $0, PID:$$\n";
# заменить текущую программу на указанную
my $program = $ARGV[0]; # имя программы в 1-м аргументе
print "Запускается программа: $program\n";
exec 'perl', $program or die; # запуск программы
print "Это сообщение никогда не напечатается!\n";
При запуске этого примера с параметром 'proc_executed.pl' будут выведены такие сообщения:
Выполняется загрузчик: proc_exec.pl, PID:652
Запускается программа: proc_executed.pl
Выполняется программа: proc_executed.pl, PID:1872
Для организации параллельного выполнения процессов в Perl используется функция fork ("разветвить"). В результате ее работы создается копия выполняющегося процесса, которая тоже запускается на выполнение. Для этого в операционных системах семейства Unix происходит обращение к системному вызову fork. В других операционных системах работа функции fork() организуется исполняющей системой Perl. Функция fork() в родительском процессе возвращает PID дочернего процесса, число 0 - в дочернем процессе и неопределенное значение при невозможности запустить параллельный процесс. Это значение проверяется в программе, чтобы организовать выполнение различных действий в процессе-предке и процессе-потомке. Как это делается, показано на следующем схематичном примере (где оба процесса в цикле выводят числа, но с разными задержками):