Используя SSH, каков наилучший способ удаленного выполнения файла perl из другого файла perl и передачи аргументов, содержащих пробелы?

#perl #ssh #arguments #space

#perl #ssh #аргументы #Космос

Вопрос:

Вот что у меня есть — скрипт CGI на сервере A получает параметры, введенные в веб-форме, создает удаленную команду ssh, которая вызывает другой файл perl на сервере B и передает все параметры в качестве аргументов команде ash . Файл Perl на сервере B анализирует аргументы n после этого работает.

Теперь, поскольку у меня не всегда будут заполняться все параметры, я передаю символ, такой как «=», добавляемый к каждому параметру из CGI на сервере A, и перед обработкой на сервере B я удаляю этот последний символ, который является «=».

Однако это не удается для параметра, который может содержать пробел. Чтобы противостоять этому, я могу заключить каждый параметр в ///» (в основном косую черту для экранирования «, а затем косую черту для экранирования другой косой черты), прежде чем добавлять «=» (который, вероятно, можно отбросить, как только я все равно вложу каждый параметр), но это лучший способ сделатьчего я хочу достичь?

Ответ №1:

Вместо вызова команды и чтения ее выходных данных я бы предложил использовать IPC ::Open2 или, возможно, IPC :: Open3 и использовать ваш процесс B в качестве фильтра: запись, считывание. На этом этапе вы полностью исключаете оболочку. И, по моему опыту, устранение оболочки всегда полезно.

А затем, чтобы все было действительно просто, вы запускаете команду через IPC::Open[23] , записываете в нее сериализованные данные (через JSON или Storable), закрываете канал записи (чтобы другая сторона получила eof) и ждете данных. На другом конце прочитайте stdin, десериализуйте его, используйте и снова сериализуйте возвращаемые данные. Вернитесь на сервер CGI, десериализуйте полученные данные и вперед. Это также очень хорошо работает, если вам нужно выполнить двойной или тройной переход (ssh через одну машину к ssh на другую).

Можно заключить достаточное количество кавычек, чтобы заставить его работать так, как вы хотите. Это умеренно болезненно. Однако вот несколько советов в этом направлении. Сначала найдите что-нибудь в CPAN, которое обрабатывает цитирование для вас. String::ShellQuote может работать. Во-вторых, избегайте оболочки, насколько это возможно. То есть вместо использования open my $pipe, "ssh $server '$cmd' |" используйте open my $pipe, '-|', 'ssh', $server, $cmd . Это позволит избежать локальной оболочки. И это уменьшает количество раз, когда вам приходится беспокоиться о цитировании чего-либо. Но вам придется повторно цитировать все каждый раз, когда вы делаете еще один отказ, поскольку каждая удаленная машина все равно будет использовать удаленную оболочку.

Ответ №2:

Используйте Net::OpenSSH, он позаботится о цитировании для вас:

 use Net::OpenSSH;

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

Ответ №3:

Я использую такой код, как

 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 );
  

Но вы могли бы использовать String::ShellQuote shell_quote вместо 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 );