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.
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";