Using SSH, what is the best way to remotely execute a perl file from another perl file and pass arguments that contain spaces?

眉间皱痕 提交于 2020-01-24 09:44:07

问题


Here is what I have- A CGI script on server A gets the parameters entered in a webform, creates a remote ssh command that calls another perl file on server B and passes all parameters as arguments to the ash command. Perl file on server B parses arguments n operates thereafter.

Now since I won't have all parameters populated at all times, I am passing a character such as "=" appended to each parameter from CGI on server A and before processing on Server B, I chop that last character which is an "=".

However, this fails for a parameter that can have space. To counter this, I can enclose each parameter within ///" (basically a slash to escape " and then a slash to escape the other slash) before I append the "="(which probably can be discarded once I enclose each param anyways), but is this the best way to do what I want to achieve?


回答1:


Rather than calling the command and reading its output, I'd suggest using IPC::Open2 or possibly IPC::Open3 and using your process B as a filter: write in, read out. At this point, you completely eliminate the shell. And, in my experience, eliminating the shell is always a good thing.

And then, to make things really simple, you run the command via IPC::Open[23], write serialised data to it (via JSON or Storable), close the write pipe (so the other side gets eof), and wait for the data. At the other end, read stdin, deserialise it, use it, and serialise your return data again. Back at the CGI server, deserialise the data you received, and away you go. This also works really well if you need to do double or triple bouncing (ssh through one machine to ssh to another).

It is possible to put in enough quotes to get it to work the way you want. It's moderately painful. However, here are some hints in that direction. First, find something on CPAN which handles the quoting for you. String::ShellQuote might work. Second, avoid the shell as much as possible. That is, instead of using open my $pipe, "ssh $server '$cmd' |", use open my $pipe, '-|', 'ssh', $server, $cmd. This will avoid the local shell. And that reduces the number of times you have to worry about quoting anything. But you will have to re-quote everything every time you do another bounce as each remote machine will still be using the remote shell.




回答2:


Use Net::OpenSSH, it will take care of the quoting for you:

use Net::OpenSSH;

my $ssh = Net::OpenSSH->new($host);
my ($out, $err) = $ssh->capture2($cmd, @args);



回答3:


I use code such as

sub text_to_shell_lit(_) {
   return $_[0] if $_[0] =~ /^[a-zA-Z0-9_\-]+\z/;  # Optional
   for (my $s = $_[0]) {
      utf8::downgrade($_);  # Check for non-bytes
      die if /\0/;          # Check for NUL
      s/'/'\\''/g;
      return "'$_'";
   }
}

my $remote_cmd = join ' ', map text_to_shell_lit,
   perl => ( '-e' => $perl_code, '--', @args );

my @ssh_cmd = (ssh => ( '--', $remote_target, $remote_cmd ));
   -or-
my $ssh_cmd = join ' ', map text_to_shell_lit,
   ssh => ( '--', $remote_target, $remote_cmd );

But you could use String::ShellQuote's shell_quote instead of text_to_shell_lit.

use String::ShellQuote qw( shell_quote );

my $remote_cmd = shell_quote
   perl => ( '-e' => $perl_code, '--', @args );

my @ssh_cmd = (ssh => ( '--', $remote_target, $remote_cmd ));
   -or-
my $ssh_cmd = shell_quote
   ssh => ( '--', $remote_target, $remote_cmd );


来源:https://stackoverflow.com/questions/7986572/using-ssh-what-is-the-best-way-to-remotely-execute-a-perl-file-from-another-per

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!