1

I am trying to implement a routine which will take in a "command" and associated "timeout". If the command completes within the specified time, it should return the output. Or else - it should kill the process.

sub runWithTimeout {

   my ($pCommand,$pTimeOut) = @_;
   my (@aResult);

   print "Executing command [$pCommand] with timeout [$pTimeOut] sec/s \n";
   eval {
        local $SIG{ALRM} = sub { die "alarm\n" };
        alarm $pTimeOut;
        @aResult = `$pCommand`;
        alarm 0;
   };
   if ($@) {
        print("Command [$pCommand] timed out\n");
        # Need to kill the process.However I don't have the PID here.
        # kill -9 pid
    } else {
        print "Command completed\n";
        #print Dumper(\@aResult);
    }
}

Sample Invocation :

&runWithTimeout('ls -lrt',5);

Executing command [ls -lrt] with timeout [5] sec/s 
Command completed


&runWithTimeout('sleep 10;ls -lrt',5);

Executing command [sleep 10;ls -lrt] with timeout [5] sec/s 
Command [sleep 10;ls -lrt] timed out

Guess if I have the PID with me - I can use "kill" on the PID in the if block.

Any pointer on how can I get the PID(or any other better approach) - it would be a great help.

Soumya
  • 885
  • 3
  • 14
  • 29

1 Answers1

2

Don't run the command with backticks, and use open instead. For bonus points - use IO::Select and can_read to see if you've got any output:

use IO::Select; 
my $pid = open ( my $output_fh, '-|', 'ls -lrt' );
my $select = IO::Select -> new ( $output_fh ); 
while ( $select -> can_read ( 5 ) ) { 
    my $line = <$output_fh>;
    print "GOT: $line"; 
}
##timed out after 5s waiting.  
kill 15, $pid;
Sobrique
  • 52,974
  • 7
  • 60
  • 101