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

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

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

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

Ответы [ 3 ]

6 голосов
/ 03 ноября 2011

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

А затем, чтобы упростить задачу, вы запускаете команду через 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.Это позволит избежать локальной оболочки.И это уменьшает количество раз, когда вам приходится беспокоиться о цитировании чего-либо.Но вам придется пересматривать все каждый раз, когда вы делаете новый отскок, поскольку каждая удаленная машина все еще будет использовать удаленную оболочку.

3 голосов
/ 03 ноября 2011

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

use Net::OpenSSH;

my $ssh = Net::OpenSSH->new($host);
my ($out, $err) = $ssh->capture2($cmd, @args);
1 голос
/ 03 ноября 2011

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

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