2009-11-17 8 views
9

В настоящее время у меня есть скрипт Perl, который запускает внешнюю команду в системе, собирает выходные данные и выполняет некоторые действия на основе того, что было возвращено. Прямо сейчас, вот как я бегу это (где $ CMD является строка с установкой команды):Как я могу запустить системную команду в Perl асинхронно?

@output = `$cmd`; 

Я хотел бы изменить это так, если команда зависания и не возвращает значение после того, как столько время, то я убью команду. Как я буду запускать это асинхронно?

ответ

8

Если вам действительно просто нужно поставить тайм-аут на заданный системный вызов, это гораздо более простая проблема, чем асинхронное программирование.

Все, что вам нужно, это alarm() внутри блока eval().

Вот пример кода, который помещает их в подпрограмму, которую вы могли бы вставить в свой код. Пример вызывает сон, так не интересно для вывода, но покажет вам функции тайм-аута вы были заинтересованы в Выход Забегая:.

/bin/спящий режим 2 отказ: тайм-аут при ./time отъезда линия 15.

$ cat time-out 
#!/usr/bin/perl 

use warnings; 
use strict; 
my $timeout = 1; 
my @cmd = qw(/bin/sleep 2); 
my $response = timeout_command($timeout, @cmd); 
print "$response\n" if (defined $response); 

sub timeout_command { 
     my $timeout = (shift); 
     my @command = @_; 
     undef [email protected]; 
     my $return = eval { 
       local($SIG{ALRM}) = sub {die "timeout";}; 
       alarm($timeout); 
       my $response; 
       open(CMD, '-|', @command) || die "couldn't run @command: $!\n"; 
       while(<CMD>) { 
         $response .= $_; 
       } 
       close(CMD) || die "Couldn't close execution of @command: $!\n"; 
       $response; 
     }; 
     alarm(0); 
     if ([email protected]) { 
       warn "@cmd failure: [email protected]\n"; 
     } 
     return $return; 
} 
+0

Спасибо, это больше того, что я искал. – Joel

+0

Думаю, вам понадобится \ n в сообщении die. (Http://perldoc.perl.org/functions/alarm.html) – ddoxey

12

Там много способов сделать это:

  • Вы можете сделать это с вилкой (perldoc -f вилка)
  • или с использованием нитей (perldoc потоков). Оба из них затрудняют передачу возвращаемой информации в основную программу.
  • В системах, которые поддерживают его, вы можете установить будильник (perldoc -f alarm), а затем очистить в обработчике сигнала.
  • Вы можете использовать цикл событий, например POE или Coro.
  • Вместо обратных шагов вы можете использовать open() или соответственно open2 или open3 (см. IPC :: Open2, IPC :: Open3), чтобы запустить программу при получении STDOUT/STDERR с помощью дескриптора файла. На нем выполняются неблокирующие операции чтения. (perldoc -f выберите и, возможно, google «perl nonblocking read»)
  • Как более мощный вариант openX(), проверьте IPC :: Run/IPC :: Cmd.
  • Наверное, я не могу думать о середине ночи.
+3

в системах win32 следить за разбитый 'select', который работает только для сокетов и потенциально странных взаимодействий с консольными окнами, wperl (работает Perl в оконном образом неконсольной, но имеет странные последствия для процессов STDIO и дочерних процессов). С положительной стороны вы можете сделать 'system (-1, 'foo')'. Кроме того, некоторые способы запуска процесса завершаются после запуска 64 детей. IME, 'Win32 :: Process :: Create()' - самый безопасный способ запуска программы в bgrnd. – daotoad

+0

@daotoad, спасибо за этот комментарий.Моя нехватка подсказки win32 показывает, что единственное, что я знаю, это то, что fork() эмулируется потоками, и вы не можете использовать будильник. Я предполагаю, что если задействован win32, IPC :: Cmd будет хорошим выбором. – tsee

1

Если внешняя программа не принимает любой входной сигнал, обратите внимание на следующие слова в perlipc страницы руководства:

Вот безопасный кавычка или трубопровод открыть для чтения:

использования пример кода и охранять его с помощью сигнала тревоги (что также объясняется в perlipc).

Смежные вопросы