in reply to
How to capture child process output and divert to log4perl
You could go for IPC::Open3, but I've had mixed results with it (because I'm too clever for my own good). I usually do a full blown pipe, fork and exec -- maybe something like:
pipe my $cin, my $pin;
pipe my $pout, my $cout;
pipe my $perr, my $cerr;
$pin->autoflush(1);
$cout->autoflush(1);
$cerr->autoflush(1);
my $pid = fork();
warn("Fork failed\n"),return unless defined $pid;
if ($pid == 0) {
# Child fork/TDE execute
close $pin;
open STDIN, "<&", $cin or die "Map fail (STDIN): $!, $?\n";
exit 1 if fileno(STDIN) != 0;
close $pout;
close STDOUT;
open STDOUT, ">&", $cout or die "Map fail (STDOUT): $!, $?\n";
exit 1 if fileno(STDOUT) != 1;
close $perr;
close STDERR;
open STDERR, ">&", $cerr or print("Map fail (STDERR): $!, $?\n
+"),exit 1;
exit 1 if fileno(STDERR) != 2;
exec $command;
}
# Parent fork/tester
return 0 if eval {
alarm $timeout;
local $SIG{ALRM} = sub {
kill 9, $pid;
die "Calculation call failed to return with $timeout secon
+ds\n";
};
close $cin;
close $cout;
close $cerr;
close $pin;
local $/; # Slurp
my $content = eof $pout ? '' : <$pout>;
my $error = eof $perr ? '' : <$perr>;
alarm 0;
unless ($content =~ /\S/) {
if ($error =~ /\S/) {
$error =~ s/^/\t/mg;
$error =~ s/\s*$/\n/;
die "No result returned; STDERR=\n$error";
} else {
die "Case Aborted: No result, no error\n";
}
} elsif ($error =~ /\S/) {
$error =~ s/^/\t/mg;
warn "$executable output to STDERR for $case$command\n$err
+or";
}
}
where obviously, you'll nee to rework the error handling a little. This will give you complete control over all 3 pipes.
#11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.