#perl
#perl
Вопрос:
Я хочу запустить некоторые тестовые исполняемые файлы с помощью скрипта perl, проанализировать их стандартный вывод и вернуть значение exit в зависимости от того, что содержал стандартный вывод. Я не очень хорошо знаком с perl, так что это было немного сложно.
Проблема, с которой я сталкиваюсь, заключается в обеспечении того, чтобы мой perl-скрипт получал все возможные выходные данные, даже если тестовые исполняемые файлы выходят из строя или зависают.
На данный момент я использую alarm для тайм-аута. Если он зависает, я бы хотел просто взять все данные, какие смогу, и продолжить синтаксический анализ. К сожалению, при моем текущем методе выполнения, если он зависает, я не получаю никаких данных, и процесс-зомби живет вечно.
Моя (вероятно, наивная) версия получения тестовых выходных данных выглядит следующим образом.
#!/usr/bin/perl
use strict;
use warnings;
my @output;
eval {
local $SIG{ALRM} = sub {die "alarmn"};
alarm 15;
@output = `testExecutable`;
alarm 0;
};
if ($@) {
die unless $@ eq "alarmn";
print "timed outn";
}
else {
print "didn't time outn";
}
print @output;
В принципе, мне нужно выполнить testExecutable таким образом, чтобы я мог получить доступ к любым данным, которые он выводит, до того, как сработает сигнал тревоги, а затем завершить процесс testExecutable в моем обработчике тревоги.
При необходимости я могу модифицировать тестовые исполняемые файлы. Оглядываясь вокруг, кажется, что буферизация может вызывать некоторую озабоченность.
Ответ №1:
Ваша проблема в том, что использование оператора обратной кавычки заполняет вашу переменную perl только по завершении. Поэтому вместо этого вы должны читать из канала perl. Итак, что-то вроде этого:
#!/usr/bin/env perl
use strict;
use warnings;
my @output;
eval {
local $SIG{ALRM} = sub {die "alarmn"};
alarm 15;
open my $pipe_handle, '-|', 'testExecutable' or die "open error: $!";
while (my $line = <$pipe_handle>) {
push @output, $line;
}
close $pipe_handle;
alarm 0;
};
if ($?) {
print "testProgram failedn";
} elsif ($@) {
die unless $@ eq "alarmn";
print "timed outn";
} else {
print "didn't time outn";
}
print @output;
Имейте в виду, что может происходить некоторая буферизация, поэтому вы все равно можете пропустить часть выходных данных.
Редактировать: Добавлено в check для $?
проверки состояния дочерней программы
Комментарии:
1. На самом деле у меня был почти такой код ранее, но, похоже, он не очень хорошо сочетался с сигналом тревоги. В отличие от обратных ссылок, он не печатал бы, что время ожидания истекло, пока я не завершу работу скрипта, и у меня все еще не было выходных данных. Тем не менее, это не было на 100% точно таким же, как ваш код, поэтому я попробую это как можно скорее.
2. Кроме того, это не касается завершения зависшего тестового процесса. Но все равно, спасибо за помощь.
3. @Slavik81 Извините, пропустил это. Добавил это, проверку на $?
4. pid дочернего процесса возвращается открытым каналом, вы можете использовать это, чтобы отключить его по истечении времени ожидания. Вероятно, вы захотите добавить еще один
alarm 15
внутри цикла, чтобы сбросить время ожидания, когда увидите какой-либо вывод.5. Это почти работает. Тем не менее, я зависаю в условном цикле while. Строка перед ним выполняется нормально, но тело цикла while никогда не выполняется, и сигнал тревоги не может вывести меня из моего зависшего состояния. A ^ C позволяет сценарию продолжать выполняться, но @output никогда не заполняется.
Ответ №2:
Запишите выходные данные внешней команды в файл и прочитайте файл, когда процесс будет завершен (обычно или по истечении времени ожидания). Как сказал Содвед, лучше всего, если вы можете заставить внешнюю программу часто очищать свои выходные данные.
my $output_file = '/tmp/foo';
eval {
local $SIG{ALRM} = sub {die "alarmn"};
alarm 15;
system("testExecutable > $output_file 2>amp;1");
alarm 0;
};
# whether successful or not, there could be output in $output_file ...
open my $fh, '<', $output_file;
@output = <$fh>;
close $fh;
unlink $output_file;
Комментарии:
1. Это действительно выводит мои данные в файл и корректно прерывается по истечении времени ожидания, так что это хорошо. Однако мне все еще нужен pid этого тестового исполняемого файла, чтобы отключить его, когда он зависает. И, вероятно, pid самого скрипта, чтобы я мог сгенерировать уникальное имя выходного файла.