Для сложных задач при запуске внешних команд IPC::Run
является довольно хорошим выбором. Следующее должно охватывать все случаи, которые вы упомянули. (Я признаю, что использование регулярного выражения в сообщении об ошибке - не самое элегантное решение, но цель здесь заключалась в демонстрации возможностей этого модуля.)
use warnings;
use strict;
use IPC::Run qw/ start timeout /;
use Try::Tiny;
my @commands = (
['perl','-e','sleep 1'], # success
['perl','-e','sleep 10'], # failure due to timeout
['perl','-e','exit 123'], # failure due to nonzero exit code
['perl','-e','kill "INT", $$'], # process exits due to signal
['this_command_doesnt_exist'], # other failure
);
for my $cmd (@commands) {
my $h;
try {
print "\nRunning ",join(' ',@$cmd),"\n";
$h = start $cmd, timeout(2);
$h->finish or die "finish with \$?=$?";
print "Success\n";
}
catch {
if (/timeout/i) {
warn "Timeout Error: $_";
warn "killing child process\n";
defined $h && $h->kill_kill;
}
elsif (/\$\?/) {
warn "Exit Code Error: $_";
# from http://perldoc.perl.org/functions/system.html
if ($? == -1) { print "failed to execute: $!\n" }
elsif ($? & 127)
{ printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without' }
else { printf "child exited with value %d\n", $? >> 8 }
}
else { warn "Other Error: $_" }
};
}
Вывод (слегка отредактирован):
Running perl -e sleep 1
Success
Running perl -e sleep 10
Timeout Error: IPC::Run: timeout on timer #2 at ...
killing child process
Running perl -e exit 123
Exit Code Error: finish with $?=31488 at ...
child exited with value 123
Running perl -e kill "INT", $$
Exit Code Error: finish with $?=2 at ...
child died with signal 2, without coredump
Running this_command_doesnt_exist
Other Error: Command 'this_command_doesnt_exist' not found in ... at ...