Perl: получить вывод из процесса в IPC :: Run, если он умирает - PullRequest
0 голосов
/ 17 мая 2018

Я выполнял некоторые команды с модулем IPC :: Run , и все в порядке, за исключением того, что я не могу получить доступ к выводу (STDOUT, STDERR), произведенный процесс и был перенаправлен в переменные,Есть ли способ получить их при обработке ошибок?

@commands = ();
foreach my $id (1..3) {
  push @commands, ["perl", "script" . $id . ".pl"];
}

foreach my $cmd (@commands) {
  my $out = "";
  my $err = "";
  my $h = harness $cmd, \undef, \$out, \$err, timeout(12,exception => {name => 'timeout'});
  eval {
    run $h;
  };

  if ($@) {
    my $err_msg = $@; # save in case another error happens
    print "$out\n";
    print "$err\n";
    $h->kill_kill;
  }
}

Пока мне не нужно ничего вводить, мне просто нужно выполнить его и получить вывод.

EDIT Я тестировал его с помощью сценариев Perl, которые выглядят следующим образом:

for (my $i = 0; $i < 10; $i++) {
  sleep 1;
  print "Hello from script 1 " . localtime() . "\n";
}

У меня есть 3 таких сценария с разным временем, а третий занимает 20 секунд, что больше, чем12 У меня в таймере.

1 Ответ

0 голосов
/ 17 мая 2018

Как отмечает @ysth, причина, по которой вы не получаете никаких выходных данных, заключается в том, что STDOUT и STDERR процесса, соответствующего команде $cmd, не являются буферизованными строками, а скорее буферизируются блоками. Таким образом, все выходные данные собираются в буфере, который не отображается (печатается) до тех пор, пока буфер не заполнится или не будет явно очищен. Однако, когда ваша команда истекает, все выходные данные все еще находятся в буфере и еще не были сброшены и, следовательно, собраны в переменную $out в родительском процессе (сценарии).

Также обратите внимание, что поскольку ваш $cmd сценарий является сценарием Perl, это поведение описано в perlvar:

$ |

Если установлено значение, отличное от нуля, вызывает сброс сразу и после каждой записи или распечатайте на текущем выбранном выходном канале. По умолчанию 0 (независимо от того, действительно ли канал буферизован системой или не; $ | говорит только, просили ли вы Perl явно сбросить после каждого пишу). STDOUT обычно будет буферизоваться строкой, если вывод в терминал и блокировать буферизованный в противном случае .

Проблема (то, что программа не подключена к терминалу или tty) также отмечена на странице документации для IPC::Run:

Интерактивные приложения обычно оптимизированы для использования человеком. Это может помогать или мешать пытаться взаимодействовать с ними через такие модули, как IPC :: Run. Часто программы изменяют свое поведение при обнаружении что stdin, stdout или stderr не связаны с tty, если что они запускаются в пакетном режиме. Помогает ли это или болит зависит от того, какие оптимизации меняются. И часто нет никакого способа рассказывать, что программа делает в этих областях, кроме проб и ошибок и иногда, читая источник. Это включает в себя разные версии и реализации одной и той же программы.

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

Одно из решений для вашего конкретного случая заключается в том, чтобы явно сделать STDOUT строку буферизованной в начале вашего скрипта:

STDOUT->autoflush(1);  # Make STDOUT line buffered
# Alternatively use: $| = 1; 
for (my $i = 0; $i < 10; $i++) {
  sleep 1;
  print "Hello from script 1 " . localtime() . "\n";
}

Редактировать

Если по какой-то причине вы не можете изменить запущенные вами скрипты, вы можете попробовать подключить скрипт к псевдотерминалу. Таким образом, вместо вставки операторов типа STDOUT->autoflush(1) в исходный код сценария, вы можете обмануть сценарий, полагая, что он подключен к терминалу и, следовательно, должен использовать буферизацию строки. Для вашего случая мы просто добавляем аргумент >pty> перед аргументом \$out в вызове harness:

my $h = harness $cmd, \undef, '>pty>', \$out,
  timeout(12, exception => {name => 'timeout'});
eval {
    run $h;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...