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...
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.eval { local $SIG{ALRM} = sub { die "TIMEDOUT" }; alarm(10); <command> alarm(0); }; if ($@) { die $@ unless $@ =~ /TIMEDOUT/; # command timed out ... } ...
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...
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?$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; }
Thanks
Back to
Seekers of Perl Wisdom