drawde83 has asked for the wisdom of the Perl Monks concerning the following question:

Hi I have a function that returns a string with multiple lines in it. This is a configuration for another program that I can run using a backtick shell. It gets the configuration through Standard input. whats the best way to get the input data into the other program?

I could probably do something like
my $data = function(); $ result = `echo $data | program`;

but I would have thought that there'd be a better way than using the echo command. I could treat it as a filehandle but then I'd be limited to only inputing data to the command or recieving it's output and I want to do both.

Replies are listed 'Best First'.
Re: piping a function into a backtick shell
by Tanktalus (Canon) on Jun 14, 2006 at 00:18 UTC

    Have you looked at IPC::Open2? This allows you to both read from and write to another program via stdout and stdin of that program. It's a bunch more work than backticks, but incredibly simpler than doing the same thing in pure C.

    Other methods include Expect, or properly quoting your string in your backticks. While that last one sounds tempting, let me dissuade you from it: it's easy to get something that usually works, but hard to get something that always works. Using IPC::Open2 will always work, once you get it working at all, because there's no nasty shell between you and your program (especialy lif you use the 'some', 'cmd', 'and', 'args' version).

Re: piping a function into a backtick shell
by rodion (Chaplain) on Jun 14, 2006 at 02:15 UTC
    You can open an output file which is a pipe to 'program', then 'print' the output of your funciton to that pipe, as in:
    open PROG, "|program" or die "Can't open output pipe to 'program'"; print PROG function(); close PROG;
    It's concise, and comes pretty close to the the goal of the code itself describing what's going on.

    Update: Oops! It's also not what you were asking for. (Sorry, I didn't read carefully, and didn't see the backticks in your code in my browser's font. )

    IPC::Open2, as Tanktalus suggests is the most concise approach under Unix. I haven't had success with IPC::Open2 under MSWindows, either XP or 98 (Perl v5.8.6 and v5.8.4 respectively). On MSWindows I think you're stuck writing to a temporary file, as in :

    my $input = "first line\nsecond line"; open TEMP, '>' "temp$$"; print TEMP $input; close TEMP; my $ouput = `type temp$$|\\vim\\vim63\\xxd.exe`; print $output; unlink "temp$$"; # (tested)
    If you're sure you won't have newlines or other troublesome characers in the '$input' data, then what you started with, using 'echo', is about as good as you'll get. (Now watch, as a much cleverer monk proves me wrong.)
Re: piping a function into a backtick shell
by graff (Chancellor) on Jun 14, 2006 at 03:59 UTC
    IPC::Open2 ought to work for this, but in case it doesn't, you could try saving the output of "function()" to a file, and running the backtick command with redirection of stdin, something like this:
    open( CONF, ">function.conf" ) or die $!; print CONF function(); close CONF; $result = `program < function.conf`;
Re: piping a function into a backtick shell
by Moron (Curate) on Jun 14, 2006 at 10:11 UTC
    It is also important to handle the pipes properly with wait to avoid creating zombies. Here is an example that enables an external middleware program called ac_bl to be the basis of a general SQL subroutine.
    use IPC::Open2; use POSIX ":sys_wait_h"; my @results = Sql( 'select ...' ); sub Sql { my $command = shift; my $options = ( shift() || '-qs' ) . ' -'; my $pid = open2 my $rh, my $wh, 'ac_bl ' . $options; write $wh $command; close $wh; my @results = <$rh>; chop @results; close $rh; waitpid $pid, 0; return @results; }
    Update: Although if this weren't a one-off I'd create a class for this with a 'fetch' method that uses wantarray to distinguish between a call that wants the lot and one that wants to fetch only one line of result output at a time.

    -M

    Free your mind