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

hi, i've been researching on this topic for quite some time, i really need help because i don't realy understand the concept of open2. what i'm trying to do is that from windows, i need to connect to linux and do a few things then exit out and back to the perl script then i'll evaluate the output from linux. To fit this purpose easily, i found plink.exe from makers of putty. however, i can't seem to retrieve the output.
#!perl use IPC::Open2; my $command = 'plink -ssh -pw password_here username_here@host_name_he +re -batch exit'; print open2(\*CIN, \*COUT, $command); close COUT; my $xs = <CIN>; print "the output is :".$xs; close CIN;
my $xs is always empty regardless. To test, i purposely put a fake username and password and i need to obtain the string 'Access denied'. However, my $xs is empty. let's say im running it from cmd prompt and i get this:
perl test.pl Access denied 3516the output is :

Replies are listed 'Best First'.
Re: assign open2 output to variable
by BrowserUk (Patriarch) on Mar 28, 2014 at 16:58 UTC

    open2 only captures output from the controlled programs stdout; the error message is being output to its stderr.

    Try: my $command = 'plink -ssh -pw password_here username_here@host_name_here -batch exit 2>&1';


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: assign open2 output to variable
by ikegami (Patriarch) on Mar 28, 2014 at 17:17 UTC

    That output is being sent to STDERR rather than STDOUT. You can easily merge the two using open3 while still avoiding to spawn a needless shell.

    use IPC::Open3 qw( open3 ); my @command = qw( plink -ssh -pw passwd user@host -batch exit ); open3(\*CIN, \*COUT, \*COUT, @command); close CIN; my $xs = <COUT>; print "the output is :".$xs; close COUT;

    Note that the order of open3's first two argument is different than open2's.

      THANKS!! this is great, i can get what i needed, i'm able to read through line by line what are the outputs. However, how will i be able to output the stream in real time while i'm collecting the data in CIN? Otherwise i'll have to flush out all outputs at one shot when the plink process is done? for this example, i'll use "ls" :
      my $command = 'link -ssh -pw password_here user_name@host -batch'; $pid= open3(\*CIN, \*COUT, \*COUT, $command); print CIN "ls\n"; print CIN "exit\n"; close CIN; my @xs = <COUT>; foreach $x(@xs) { print "\noutput:".$x."\n"; } close COUT; waitpid( $pid, 0 );
        The following will print the output as its produced:
        while (<COUT>) { print; }

        Well, it prints it a line at a time. sysread can truly get it as its produced.

        Of course, plink might buffer its output. Lots of applications do when they're output isn't a terminal. If it does, you'll have to look if it provides a way to be told not to.

Re: assign open2 output to variable
by kcott (Archbishop) on Mar 28, 2014 at 17:30 UTC

    G'day adrivez,

    Welcome to the monastery.

    "hi, i've been researching on this topic for quite some time"

    Did your research include reading the IPC::Open2 documentation?

    Based on that documentation, here's an example which I think emulates what you're trying to do:

    #!/usr/bin/env perl use strict; use warnings; use autodie; use IPC::Open2; my $pid = open2(my $child_out, my $child_in, 'date'); my $from_child = <$child_out>; print 'From child: ', $from_child; waitpid $pid, 0; print 'Child exit status: ', $? >> 8, "\n";

    Output:

    From child: Sat 29 Mar 2014 03:49:33 EST Child exit status: 0

    Note how my code reflects the documented example while yours bears little resemblance. As there's only a few lines of code, I suggest you compare the scripts: see where I've followed the documentation and ask yourself why you've done things differently — this may help you understand where you've gone wrong.

    Also note that calling $child_out CIN and calling $child_in COUT will only serve to confuse you: it had me scratching my head when I first saw it!

    [strict, warnings and autodie are all documented in Pragmas. You should use the first two of those in all your scripts!]

    I'm not familiar with plink. What output do you get when you run the command you've posted from the command line? Does the output go to STDOUT or STDERR? If the latter, then you'll need IPC::Open3 to capture it.

    There's further information in "perlipc: Bidirectional Communication with Another Process".

    -- Ken

      FYI: plink is PuTTY's command line version of ssh.

      --MidLifeXis

Re: assign open2 output to variable
by ikegami (Patriarch) on Mar 28, 2014 at 17:14 UTC
    CIN for the child's output, and COUT for the child's input? You've picked very confusing names.
Re: assign open2 output to variable
by adrivez (Initiate) on Mar 29, 2014 at 07:10 UTC
    THANKS!! this is great, i can get what i needed, i'm able to read through line by line what are the outputs. However, how will i be able to output the stream in real time while i'm collecting the data in CIN? Otherwise i'll have to flush out all outputs at one shot when the plink process is done? for this example, i'll use "ls" : my $command = 'link -ssh -pw password_here user_name@host -batch';
    $pid= open3(\*CIN, \*COUT, \*COUT, $command); print CIN "ls\n"; print CIN "exit\n"; close CIN; my @xs = <COUT>; foreach $x(@xs) { print "\noutput:".$x."\n"; } close COUT; waitpid( $pid, 0 );