简体   繁体   中英

Perl how to properly handle System Commands (including Timeout with Kill & capture of RC/STDERR/STDOUT)

From a Perl script I want to execute various system commands and process the output in my script.

The script will be run automatically, so I want to make sure that no commands are hanging etc.

I'm open to any kind of feedback.

My requirements for the command execution:

  • Timeout -> If command runs longer than XX Seconds, it should kill its process(es)
  • If command returns information, it should not have to wait for end of timeout
  • I want to capture the exit status, STDERR, STDOUT in the script.

Here is an example I worked out from an other stackoverflow question: Kill a hung child process

What's not working for me at the moment:

  • cannot capture exit status of executed command
  • cannot capture STDERR of executed command

Code:

my $cmd = "sleep 15"; # other tests i use -> "echo bla" and "alkjdsf"
my $TIMEOUT = 10;

my $pid = open my $proc, '-|', "$cmd";

if (fork() == 0) {
    my $poor_mans_alarm = "sleep 1,kill 0,$pid ||exit for 1..$TIMEOUT;kill 9,$pid";
    # run poor man's alarm in a background process
    exec($^X, '-e', "$poor_mans_alarm");
}

my $process_output = "";
while (<$proc>) {
   $process_output .= $_;
}

If you either have a trick for this code or recommend a completely different solution, let me know.

Thanks and cheers



Addition:

Got a working Example with IPC::Open3, But for future reader please Check out IPC::Run which has a Timeout Functionality included, as mentioned by James Green.

Working example with IPC::Open3:

my $pid = open3(\*WRITE, \*READ,\*ERROR,"$command");

if (fork() == 0) {
    my $poor_mans_alarm = "sleep 1,kill 0,$pid ||exit for 1..10;kill 9,$pid";
    # run poor man's alarm in a background process
    exec($^X, '-e', "$poor_mans_alarm");
}


# get all the STDOUT and STDERR from the Child.
while (<READ>) {
   $output .= $_;
}

while (<ERROR>) {
   $output .= $_;
}

waitpid($pid, 0);
if ($?) {
    $rc = $? >> 8;
    if ($rc != 1){
        print "Some error $?\n";
    }
}

It looks like IPC::Run provides pretty much everything you're after, including timeouts and capture of both STDOUT and STDERR. Docs are at https://metacpan.org/pod/IPC::Run including some usage examples.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM