How can I run a process from Perl and capture both

2019-09-12 15:19发布

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?

5条回答
来,给爷笑一个
2楼-- · 2019-09-12 15:33

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;
查看更多
Root(大扎)
3楼-- · 2019-09-12 15:41

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.

查看更多
Root(大扎)
4楼-- · 2019-09-12 15:44

You can try IPC::Run.

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

查看更多
We Are One
5楼-- · 2019-09-12 15:51

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";
查看更多
何必那么认真
6楼-- · 2019-09-12 15:52
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.

查看更多
登录 后发表回答