The perldoc man page for IPC::Open3 is a bit quizical on this point; first it says "If ERRFH is false, or the same file descriptor as RDRFH, then STDOUT and STDERR of the child are on the same filehandle." Later it says "If either reader or writer is the null string, this will be replaced by an autogenerated filehandle."
Okay, so in your case, $in and $out are "null strings", hence they get replaced by autogenerated filehandles. Then, $err happens to be false (same thing as a "null string", you might say, but that's not what matters -- at the point where you pass it to open3, its value is false), hence it becomes a dup of the child's STDOUT.
I hadn't played with open3() much before now, so it took me a few tries to get a working demo, but here it is. First, a simple, dumb child script that writes to STDOUT and STDERR:
#!/usr/bin/perl
use strict;
use IO::Handle;
autoflush STDOUT 1; # had to do this, even tho Open3 doc said it woul
+d be done already
while (<>) {
chomp;
print "line $. to STDOUT: $_\n";
warn "mesg $. to STDERR\n";
}
Then, a simple, dumb parent to run the child:
#!/usr/bin/perl
use strict;
use IPC::Open3;
my $cmd = "test-child.pl";
my ( $in, $out, $err );
$err = "true"; # any string will do (don't use a number)
my $pid = open3( $in, $out, $err, $cmd );
my ( $outlog, $errlog );
for ( 1..3 ) {
print $in "data $_\n";
$outlog .= <$out>;
$errlog .= <$err>;
}
close $in;
waitpid $pid, 0;
print "outlog contained:\n$outlog\n";
print "errlog contained:\n$errlog\n";
__OUTPUT__
outlog contained:
line 1 to STDOUT: data 1
line 2 to STDOUT: data 2
line 3 to STDOUT: data 3
errlog contained:
mesg 1 to STDERR
mesg 2 to STDERR
mesg 3 to STDERR
Anyway, to answer your question: I suppose the "if ERRFH is false, set it equal to RDRFH" behavior makes the "simplest default" case come out as "STDERR eq STDOUT" because that's the way shells usually work when returning process output to an interactive user: unless the user specifies otherwise in an interactive shell, stdout and stderr are both presented to the screen.
Okay, as a rationale, that probably makes no sense in the non-interactive context of a perl script. Oh well...
(update: to clarify about setting autoflush in the child, that actually makes sense: open3() can only control the properties of filehandles in the parent, and one of its big caveats is that it only works properly when the child is itself configured so as not to buffer its output. I could have done "$| = 1" in the child, instead of using IO::Handle's autoflush call, and it would work just as well.) | [reply] [d/l] [select] |
As I said in the OP I got it working, I understand what the behavior is. What I don't understand is the design decision to make it work that way. Was just trying to figure out if there was a reason I'm not seeing.
| [reply] |
In the code for IPC::Open3, if you set the third (stderr) filehandle to 0, stderr will be sent to stdout
#my $pid = open3(\*WRITE, \*READ, \*ERROR,"bc");
my $pid = open3(\*WRITE, \*READ,0,"bc");
#if \*ERROR is false, STDERR is sent to STDOUT
Also in your code you have 2 while loops, one for $out and one for $err. You will be better off using IO::Select to read the filehandles, otherwise the first while loop will "block" unless it's properly constructed.
I'm not really a human, but I play one on earth.
flash japh
| [reply] [d/l] |