Skip to content

Instantly share code, notes, and snippets.

@andrewyatz
Created March 2, 2011 21:54
Show Gist options
  • Save andrewyatz/851832 to your computer and use it in GitHub Desktop.
Save andrewyatz/851832 to your computer and use it in GitHub Desktop.
Spawning, selecting STDOUT/STDERR & reaping an external process in Perl
use strict;
use warnings;
use IPC::Open3;
use IO::Select;
my $debug = 1;
my $cmd = 'do something on the system';
my ($in_fh, $out_fh, $err_fh);
$err_fh = gensym(); #Need to do otherwise open3 clobbers STDOUT & STDERR
my $pid;
print STDOUT 'Running command: '.$cmd, "\n" if $debug;
eval{
$pid = open3($in_fh, $out_fh, $err_fh, $cmd);
};
die "open3: $@\n" if $@;
# print $in_fh 'print to process if required';
close($in_fh) or die "Could not close the STDIN to ${cmd}: $! \n";
my $out = '';
my $err = '';
my $sel = IO::Select->new();
$sel->add($out_fh, $err_fh);
while(my @ready = $sel->can_read) {
foreach my $fh (@ready) {
my $line;
my $len = sysread($fh, $line, 4096); #Read 4KB at a time
#Error occured
if(not defined $len){
die("Error from child: $!\n");
}
elsif ($len == 0) {
#End of info from file handle so we finish & remove it
$sel->remove($fh);
next;
}
#Got data to read
else {
if($fh == $out_fh) {
$out .= $line;
}
elsif($fh == $err_fh) {
$err .= $line;
print STDERR $err if $debug;
}
else {
die("Odd error as we have somehow got a FH we do not know about\n")
}
}
}
}
waitpid $pid, 0;
my $child_exit_status = $? >> 8;
#Die if we lacked a non-0 exit code
if($child_exit_status != 0) {
die("Error detected when running ${cmd}. Exit status was ${child_exit_status}. STDERR was: ${err}\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment