Created
October 15, 2013 09:21
-
-
Save shalk/6988937 to your computer and use it in GitHub Desktop.
usage of IPC::Open3 with IO::Select http://www.perlmonks.org/?node_id=150748
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################################### | |
#!/usr/bin/perl -w | |
# this script printf to stdout and stderr. It prints random | |
# characters and does not flush the output of stdout. stderr | |
# is autoflushed by default. | |
# uncomment the line about autoflush STDOUT to see how that | |
# changes the behavior. Also, you can uncomment the sleep | |
# line to watch the script in slow motion. | |
use warnings; | |
use strict; | |
use IO::Handle; | |
#autoflush STDOUT 1; | |
for (1..100){ | |
my $str = ''; | |
for(1..80){ | |
$str .= ('A'..'Z','a'..'z',0..9)[rand 62]; | |
} | |
if(int rand 2){ # 50:50 chance | |
print STDOUT "StdOut:$str"; | |
} else { | |
print STDERR "StdErr:$str"; | |
} | |
# sleep 1; | |
} | |
############################################################ | |
#!/usr/bin/perl -w | |
# this script runs the previous script and catches both | |
# child's stdout and stderr. It prints progress information | |
# as it goes. It also prints the data it gets to the | |
# corresponding file. | |
use strict; | |
use warnings; | |
#use diagnostics; | |
use IPC::Open3; | |
use IO::Select; | |
use Symbol; | |
my $cmd = "./test.pl"; | |
open(ERRLOG, ">error.log") or die "Can't open error log! $!"; | |
open(OUTPUT, ">output.log") or die "Can't open output log! $!"; | |
my ($infh,$outfh,$errfh); | |
$errfh = gensym(); # if you uncomment this line, $errfh will | |
# never be initialized for you and you | |
# will get a warning in the next print | |
# line. | |
my $pid; | |
eval{ | |
$pid = open3($infh, $outfh, $errfh, $cmd); | |
}; | |
die $@ if $@; | |
print "IN: $infh OUT: $outfh ERR: $errfh\n"; | |
print "PID was $pid\n"; | |
# now our child is running, happily printing to | |
# its stdout and stderr (our $outfh and $errfh). | |
my $sel = new IO::Select; # create a select object | |
$sel->add($outfh,$errfh); # and add the fhs | |
# $sel->can_read will block until there is data available | |
# on one or more fhs | |
while(my @ready = $sel->can_read) { | |
# now we have a list of all fhs that we can read from | |
foreach my $fh (@ready) { # loop through them | |
my $line; | |
# read up to 4096 bytes from this fh. | |
# if there is less than 4096 bytes, we'll only get | |
# those available bytes and won't block. If there | |
# is more than 4096 bytes, we'll only read 4096 and | |
# wait for the next iteration through the loop to | |
# read the rest. | |
my $len = sysread $fh, $line, 4096; | |
if(not defined $len){ | |
# There was an error reading | |
die "Error from child: $!\n"; | |
} elsif ($len == 0){ | |
# Finished reading from this FH because we read | |
# 0 bytes. Remove this handle from $sel. | |
# we will exit the loop once we remove all file | |
# handles ($outfh and $errfh). | |
$sel->remove($fh); | |
next; | |
} else { # we read data alright | |
print "Read $len bytes from $fh\n"; | |
if($fh == $outfh) { | |
print OUTPUT $line; | |
} elsif($fh == $errfh) { | |
print ERRLOG $line; | |
} else { | |
die "Shouldn't be here\n"; | |
} | |
} | |
} | |
} | |
# now that the child closed both its handles, I assume it | |
# exited. | |
# ps will show you the <defunct> child. | |
print `ps`; | |
# go ahead and reap it | |
waitpid $pid, 0; # wait for it to die | |
# not it's no more | |
print `ps`; | |
close(ERRLOG) or die "Can't close filehandle! $!"; | |
close(OUTPUT) or die "Can't close filehandle! $!"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment