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

I want to run a command which results in the user being prompted several times for some input.
It would be easy to create a text file with the inputs and then run the command like:

@output = `cmd < textfile`;

My problem - I want to retrieve and process the output after each input and not just at the end.

I thought that the best way to do this would be to open a filehandle like this:

open (P1, "|cmd"); print P1 'input1'; # process output print P1 'input2'; # process output print P1 'input3'; close P1; # process final output

However, I cannot get this to work successfully.
Am I on the right track or is there a better way?
Any help greatly appreciated

Replies are listed 'Best First'.
Re: Process command output after each input
by Paladin (Vicar) on Dec 02, 2004 at 23:35 UTC
    To open a process for both reading and writing take a look at the IPC::Open2 module.
Re: Process command output after each input
by tall_man (Parson) on Dec 02, 2004 at 23:55 UTC
    For more complex cases where you may get different sequences of prompts, I would recommend the Expect module.
    use strict; use Expect; ... # This sample code is adapted from the Expect man page, # and is not tested. my $exp = Expect->spawn($command, @params) or die "Cannot spawn $command: $!\n"; $exp->send("string\n"); my ($matched_pattern_position, $error, $successfully_matching_string, $before_match, $after_match) = $exp->expect($timeout, @match_patterns);
Re: Process command output after each input
by zentara (Cardinal) on Dec 03, 2004 at 12:00 UTC
    You are on the right track, but you need something that will let you read and write to the external application.IPC::Open3 is the easiest way. IPC::Open2 works just as well but you don't have a way of getting STDERR unless you do a "$cmd 2>&1"

    An IPC::Open2 example( put it in a loop if needed):

    #!/usr/bin/perl #prompts for an string to evalute #(line 2+2, or 5x7, 5*6 / 3 , etc) #sends it to the bc calculator, #then reads the answer, and prints. use IPC::Open2; use strict; use warnings; my ($rd, $wr); open2($rd, $wr, "bc"); print "Enter a string to evaluate\n"; my $prompt= <STDIN>; print $wr "$prompt"; my $x = <$rd>; print $x; close($rd); close($wr);

    A simple IPC::Open3 example

    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; #interface to "bc" calculator #my $pid = open3(\*WRITE, \*READ, \*ERROR,"bc"); my $pid = open3(\*WRITE, \*READ,0,"bc"); #if \*ERROR is false, STDERR is sent to STDOUT while(1){ print "Enter expression for bc, i.e. 2 + 2\n"; chomp(my $query = <STDIN>); #send query to bc print WRITE "$query\n"; select(undef,undef,undef,2); #get the answer from bc chomp(my $answer = <READ>); print "$query = $answer\n"; } waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created.

    A more complex IPC::Open3 example:

    #!/usr/bin/perl use warnings; use strict; use IPC::Open3; use IO::Select; #interface to "bc" calculator my $pid = open3(\*WRITE, \*READ,\*ERROR,"bc"); my $sel = new IO::Select(); $sel->add(\*READ); $sel->add(\*ERROR); my($error,$answer)=('',''); while(1){ print "Enter expression for bc, i.e. 2 + 2\n"; chomp(my $query = <STDIN>); #send query to bc print WRITE "$query\n"; foreach my $h ($sel->can_read) { my $buf = ''; if ($h eq \*ERROR) { sysread(ERROR,$buf,4096); if($buf){print "ERROR-> $buf\n"} } else { sysread(READ,$buf,4096); if($buf){print "$query = $buf\n"} } } } waitpid($pid, 1); # It is important to waitpid on your child process, # otherwise zombies could be created.

    I'm not really a human, but I play one on earth. flash japh

      The paragraph entitled 'A more complex IPC::Open3 example' was just what I needed but I now have a requirement to do this for Windows as well as Unix.

      Any ideas as I can't get it to work for Windows??

        Sorry, I don't run or test anything on windows. From previous posts regarding this, there is some sort of problem on windows, and it is suggested to try the IPC::Run module, which communicates via sockets, instead of pipes, and it reported to work well on windows.

        I'm not really a human, but I play one on earth. flash japh
      Hi,
      I want to know how can i do the following in my perl program
      I am calling "open3 (a,b,c,$cmd)" - $cmd is some other unix command that asks for user input via STDIN. (real example: unix ci command -- check-in file to RCS and it needs some message).
      I am really confused how to attach STDIN between the parent and child using open3
      thanks
      ankur
        Read perldoc IPC::Open3. The 'a' is STDIN to your program, the 'b' is STDOUT, and 'c' is STDERR, (which will be combined into STDOUT if 0 ). So to send a command to $cmd, just " print a 'my_message_to_send' ", where 'a' is the filehandle. That's why it's called IPC Open3 , it opens 3 filehandles to your program.

        I'm not really a human, but I play one on earth. flash japh
Re: Process command output after each input
by barryr (Initiate) on Dec 06, 2004 at 00:58 UTC

    To all reples thank you very much!!
    This has been excellent.
    To zentara in particular - your response was perfect for my needs