How can I run a process from Perl and capture both

2019-09-12 14:56发布

问题:

I would like to run a separate process in Perl (a command line PHP script). I would like to capture this processes output AND return code. Optionally I would like to be able to terminate the process and move on if the process takes longer than N seconds. What should I look into?

回答1:

You can try IPC::Run.

IPC::Run - system() and background procs w/ piping, redirs, ptys (Unix, Win32)



回答2:

use IPC::System::Simple qw/EXIT_ANY $EXITVAL capture/;

my $output = capture(EXIT_ANY, 'some command');
print "exit value was $EXITVAL\n";

EXIT_ANY tells capture to allow any exit value; you can instead list allowed ones (capture([0,1,42], ...)) and capture will throw an exception if another is encountered. By default (if just a command is passed to capture) any non-zero exit value results in an exception.



回答3:

Personally, I find the easiest is AnyEvent with AnyEvent::Util::run_cmd and a timer. There is no requirement here to run your entire program under an event loop, I regularly go in and out of the event loops with this solution today. (The following isn't warnings-safe.)

use AnyEvent;
use AnyEvent::Util;

my ($stdout, $stderr, $pid);

my $cv = AnyEvent::Util::run_cmd [ $^X, -e => '$|++; sleep 2; print "foo\n"; sleep 2' ],
    '>'  => \$stdout,
    '2>' => \$stderr,
    '$$' => \$pid,
;

my $w = AnyEvent->timer(after => 3, interval => 0, cb => sub { print "killing!\n"; kill SIGINT => $pid });

my $rc = $cv->recv();
$w = undef; # end the timer.

print "got rc = [$rc]\n";
print "stdout = [$stdout]\n";
print "stderr = [$stderr]\n";


回答4:

This is a frequently asked question. Have a look at this Perl FAQ too. It basically explains the way to run external commands in Perl.



回答5:

You can use piped open() to get all 3 goals:

my $pid = open(F, "cat /etc/passwd |") || die "Cant open pipe: $!";
eval {
     # Give 30 secs to read output:
     local $SIG{ALRM} = sub { kill(9, $pid); die "alarm\n"; }; # NB: \n required
     alarm(30);

     # Read output:
     my $line = <F>;
     alarm(0); # Remove alarm

     #..do job with $line
};
# Get errorcode:
close(F);
print "Exit status: $?\n";
printf "Exit value(return code): %d\n", $?>>8;
print "Killed by timeout\n" if ($? & 127)==9;