http://www.perlmonks.org?node_id=77188

bluto has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to figure out an effective way of timing out shell commands in Perl. At several places I've looked the canonical solution appears to be something like...
eval { local $SIG{ALRM} = sub { die "TIMEDOUT" }; alarm(10); <command> alarm(0); }; if ($@) { die $@ unless $@ =~ /TIMEDOUT/; # command timed out ... } ...
If "command" is an internal perl command this works fine. If it is an external comand (e.g. system(), backticks, etc.) the code above is executed just fine, but the child continues to execute as well rather than dying on the spot.

I guess I should expect this since I'm assuming that the exception has longjmp'd past the code that would reap the child. I suppose another way of handling this would be to use a pipe open like this...

$pid = open(PIPE, "$command |") or die $!; eval { local $SIG{ALRM} = sub { die "TIMEDOUT" }; alarm(10); while (<PIPE>) { <do whatever> }; close(PIPE); alarm(0); }; if ($@) { die $@ unless $@ =~ /TIMEDOUT/; kill 9, $pid; close(PIPE); ## needed?? $? ||= 9; }
I'm probably being overly paranoind, but this all seems rather cheesy. If the close is outside the eval, it seems like it won't catch cases where the child closes STDOUT/STDERR but decides not to quit (not sure if that happens much). If it is inside the eval, as above, will things get cleaned up properly within Perl if the code breaks out while in the close? Is there something better?

Thanks