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, '<', "" 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", 
            # tell plink to use 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 && ./ \"$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";


  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:

    Also, someone wrote a module for IronPython:

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

  2. Gene

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

    • james

      I just try till it works. Sometimes only later do I figure out why I can/can’t do something 🙂

  3. marlene

    Thank you!!!!

  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?


    • 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.


Submit a Comment

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

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.

You May Also Like…

Clear HSTS Settings in CHrome

Open chrome://net-internals/#hsts enter the domain in the query field and click Query to confirm it has HSTS settings...

Ubuntu on Hyper-v

It boils town to installing linux-azure # as root or sudo apt-get update apt-get install linux-azure...