Slash Boxes
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

polettix (7564)

  (email not shown publicly)

Journal of polettix (7564)

Friday March 30, 2007
06:23 PM

IPC::Open3 quirks

[ #32851 ]

I sometimes record some modules as possible "future save-the-day solutions" when I read about them, mostly on Perl Monks. One of these modules is IPC::Open3, but I'd take more care in ensuring these safe nets.

IPC::Open3 is useful when you want complete input/output control on a spawned process, i.e. when you have to control its STDIN, STDOUT and STDERR as well. The interface is quite straightforward:

$pid = open3(\*WTRFH, \*RDRFH, \*ERRFH,
             'some cmd and args', 'optarg', ...);

my($wtr, $rdr, $err);
$pid = open3($wtr, $rdr, $err,
             'some cmd and args', 'optarg', ...);

One thing that the docs state quite clearly is the following:

If ERRFH is false, or the same file descriptor as RDRFH, then STDOUT and STDERR of the child are on the same filehandle.

It's easy (at least for me) to overlook this, and you can imagine my surprise discovering that all the STDERR of the spawned process goes straight to STDOUT, and the filehandle for $err is undefined. What's not so easy is to discover how one can address this issue. IMHO, the "Do What I Mean" mantra has been spectacularly betrayed here, where I would expect a brand new handle to be created for me. Just like $wtr and $rdr, you know. Just like the filehandle in open().

Thanks to this thread, I discovered one solution to the problem: gensym. Here's a working snippet, at last:

# see also

use strict;
use warnings;
use IPC::Open3 qw( open3 );
use Symbol;    # provides gensym

my ($in, $out, $err);
$err = gensym();  # Aha! This was what I was after
my $pid = open3($in, $out, $err, '/bin/ls', '/path/to/inexistent', '/tmp')
  or die "open3(): $!";

my @emsg = <$err>; # The error comes from here
print {*STDOUT} "process STDERR: @emsg\n" if @emsg;

my @omsg = <$out>; # Output for existing stuff
print {*STDOUT} "process STDOUT @omsg\n" if @omsg;


poletti@PolettiX:~/sviluppo/perl$ perl
process STDERR: /bin/ls: /path/to/inexistent: No such file or directory

process STDOUT /tmp:

Something to remember well for the future...

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
More | Login | Reply
Loading... please wait.