views:

55

answers:

1

In perl, I often need to run a child process, send some input to it, and then read its output. There are a number of modules to do this, but they all seem to require you to pass in pre-existing variables, which are then modified by the function to contain filehandles. Here is an example from the Synopsis of IPC::Open3:

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

This pattern gets kind of annoying when I have to do it over and over, especially because it involves a bunch of positional parameters that I need to either remember or look up. Is there any module out there that provides a function (let's call it myopen3) that works like the following?

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

Or it could return a hash or hashref of the relevant handles:

my $process = myopen3('some cmd and args', 'optarg', ...);
$process->{STDIN}->print("Some input");
my $output = $process->{STDOUT}->readline;

The advantages of such a function are that myopen3 is called in exactly the same way as the builtin system (though hopefully without some quirks), and in the case of returning a hash or hashref, positional parameters and return values are avoided. (Also, if the module author later decided to also return the pid and other information about the process, that could be done while maintaining backwards-compatibility.)

I actually implemented this myself (with a simple OO interface), but I would rather not rely on my own custom module if a CPAN module exists to do the same thing.

The closest I've found so far is IPC::RunSession::Simple, which returns an object with reader and writer methods. However, the reader method merges STDOUT and STDERR of the child process, while I would like the option to separate them.

+5  A: 

Just write your own:

sub myopen3
{
    my ($err, $in, $out);
    my $pid = open3($in, $out, $err, @_);
    return ($pid, $in, $out, $err);
}
JSBangs
Don't forget to initialize `$err` (see the `... = gensym` trick in the OP) before calling `open3`.
mobrule
I've written my own module for it, but if a module already exists on CPAN to do the same thing, that makes my life easier when I copy my scripts to another computer, because I don't have to also copy over my custom module and install it. But yes, my current solution is to do it myself.
Ryan Thompson
Get a PAUSE account, or learn to love mcpani.
hobbs