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

I have tried Super Search, CPAN, Google and the Perl Cookbook but perhaps the Monks can save me from thinking I am trying to do the impossible.

What I would like to do is start up an external program (talk or telnet for example), send it some data via STDIN, and then return STDIN of the program to the controlling console. I would like to avoid having the Perl process sitting around redirecting output the whole time.

Here is the code I have so far:

#!/usr/bin/perl use strict; my $cmd = "telnet"; # or talk my $args = "testhost"; # or user my $data = "my_name\nmy_pass\n\nstartup_cmd\n"; # or "hi user\n" print "Running '$cmd' with '$args', and sending '$data'\n"; local $^F = 1000; # set max system file descriptor high! pipe(READ,WRITE); select((select(READ), $| = 1)[0]); if (my $pid = fork) { # PARENT - launches the program #close(WRITE); # don't close the pipe, and '$cmd' doesn't die! :-) # One way, reopen stdin to the pipe: open(STDIN, "<&READ"); exec "$cmd $args"; # Another way, mess with file descriptors # and shell redirection: #my $fd = fileno(READ); #print "fd = $fd\n"; #exec "$cmd $args <&$fd"; # similarly, try to grab STDIN as well: #exec "$cmd $args <&$fd &0<&$fd"; # (however, seems to separate '$cmd' from the console) die "exec of '$cmd' failed. $!"; } else { # CHILD - sends the data close(STDIN); close(STDOUT); close(STDERR); close(READ); print WRITE "$data\n"; # Almost there, but instead of exiting, I need # to set WRITE back to the controlling console exit; }
I need something like the shell command "fg" to perform the missing piece. Other modules that I have looked at, but don't seem to _quite_ do what I need include Proc::Spawn, IPC::Run, and IO::Handle.

Is there any deep perl magic that can help me, or am I just wishing for something that can't be done?

Thanks, Nathan

Replies are listed 'Best First'.
Re: Send data to STDIN of a exec'ed program
by iburrell (Chaplain) on Nov 14, 2002 at 17:52 UTC
    What do you mean by "return STDIN of the program to the controlling console"? Do you mean send *stdout* of the program to the console? Or redirect stdin to the console once the Perl process is finished writing to the child?

    Instead of doing the fork and pipe you can do:

    open(CHILD, "| $command") or die "$command failed: $!\n";
      What do you mean by "return STDIN of the program to the controlling console"? Do you mean send *stdout* of the program to the console? Or redirect stdin to the console once the Perl process is finished writing to the child?

      I would like to be able to redirect STDIN of the exec'ed process to the console, once the child process has finished writing the data to it.

      (The open from pipe trick is nice, but I thought pipe/fork would give me more flexibility.)

      Thanks, Nathan

        I would like to be able to redirect STDIN of the exec'ed process to the console, once the child process has finished writing the data to it.

        I'm sorry I have to say this. what you said is not what you want. what it sounds like to me is:
        you want to run a script that takes STDIN and sends it both to the child process and to the console.
        what it sounded like you said was:
        you want to pull the date the the exec'ed program just took in out of it and send it to the console and back to the program that was called.

        jjdraco
        learning Perl one statement at a time.
Re: Send data to STDIN of a exec'ed program
by dws (Chancellor) on Nov 14, 2002 at 19:39 UTC
    Have you looked at open2()? It's described in perlipc. If you're running 5.8, there's alsoIPC::Open2.

      I did look at open2. As with open from pipe, there is more than one way to do what I already have. I thought that the extra file handles from pipe/fork would allow for shell redirection tricks. But, alas, it has not helped much. :-(

      Any other ideas for taking the next step?

Re: Send data to STDIN of a exec'ed program
by zentara (Cardinal) on Nov 15, 2002 at 16:23 UTC
    I'm kind of lost as to what you are trying to do. But here is 
    an example using IPC::Open3, that might give you some ideas.
    After experimenting around with IPC , and pipes etc., I've
    come to the conclusion that "sockets" is the best way to
    deal with having programs talk to one another, pipes are
    too limited.
    
    ############################################
    #!/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";
    
    #get the answer from bc 
    chomp(my $answer = <READ>);
    
    print "$query = $answer\n";
    }
    ########################################