plink.exe – Unable to read from standard input: The handle is invalid.

Written by James McDonald

September 25, 2008

I am currently writing a small wxPerl application on Windows that will take user input and then send that input via ssh to a Linux server for further processing.

I am using PuTTY’s command line component plink.exe for this.

To stop the wxPerl program launching a DOS box, you need to run it via wperl.exe which closes STDIN STDOUT STDERR. Once I ran the wxPerl program using wperl.exe the system() call to plink.exe failed with “Unable to read from standard input: The handle is invalid.” The error seems to be a bug in plink.exe that the developers are aware of. So it may be fixed in future.

The work-a-round:

Redirect STDIN, STDOUT, STDERR to a file

open STDIN, '<', "std.in" or die "Can't redirect STDIN: $!";
open STDOUT, '>', "std.out" or die "Can't redirect STDOUT: $!";
open STDERR, ">STDOUT" or die "Can't dup STDOUT: $!";

Redirecting STDERR to the same file as STDOUT means you can get your error messages inserted in chronological order into what was being output at the time. If you send STDERR to it’s own file you have to guess where a particular error occurred.

The interesting part of the problem was I didn’t know plink was throwing that error until I did the above change then the contents of std.out told me what had been happening.

The code to call plink.exe and execute commands on a remote server from Perl is as follows. It’s split over several lines for readability. Note the extensive use of backslash escapes and only using double quotes ” so that the variables can be interpolated (a fancy word I read in the Perl cookbook).

my @args = ("plink.exe", 
            # -l defines the next arg as the username to login as
            "-l", "rupert", 
            "-t", 
            "rupert\@theLinuxServerAddress",
            # tell plink to use ssh
            "-ssh", 
            # command/s to run on the remote server
            # in this case change directory and 
            # if successful run a perl script with multiple arguments
            # which because of the complicated 
            # backslash escaping can be passed in further up the script
            "\"cd /home/rupert/anotherdir && ./myremoteperl.pl \"$arg_1\" \\\"$arg_2 a value which contains spaces\\\" \"$arg_3\" \"$arg_4\" \"$arg_5\"\"" ) ;

system(@args) == 0 or die "can't run @args : $?\n";

6 Comments

  1. Matt

    I’m attempting the same with os.popen() for python (I’m using IronPython); and get the same outcome.

    In order to take output, you can use the subprocess module, which allows many more options for the os.popen function. Which is all good, except that subprocess isn’t functional in IronPython πŸ™

    There is an example of utilizing the .NET framework to do the same thing: http://www.nabble.com/Re%3A-import-subprocess-p11453726.html

    Also, someone wrote a module for IronPython: http://www.ualberta.ca/~jdhardy/subprocess.py

    I’ll take a look at your work-around and see if it also applies to IronPython. Thanks!

    Reply
  2. Gene

    thanks, I was sitting here and scratching my head over the same issue. All I needed was one little “\”

    Reply
    • james

      I just try till it works. Sometimes only later do I figure out why I can/can’t do something πŸ™‚

      Reply
  3. marlene

    Thank you!!!!

    Reply
  4. Dirk

    Hi there,

    I have a similar problem when launching plink form within Latex. I’m not sure however how to translate your solution to there. Any ideas?

    Dirk

    Reply
    • James

      Perhaps post the error message or the code that is calling plink.exe we may be able to figure out what is going on with it.

      Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

You May Also Like…

How to Research a CPU Upgrade

How to Research a CPU Upgrade

Upgrade Time! Doing a lot of VMWare Workstation virtualization to create labs for self-study and training. Finding...