Вызов команды оболочки с несколькими аргументами - PullRequest
0 голосов
/ 27 мая 2018

Я пытаюсь автоматизировать создание сертификатов с помощью скрипта Perl.

Команда, которую я хочу выполнить:

easyrsa build-client-full $clientname nopass

То, как я думал, это должно быть сделано в Perl,:

   my $arguments = ("build-client-full $clientname nopass");       
   my $cmd = "$easyrsa_path/easyrsa"." "."$arguments";
   system("bash", $cmd);

Однако это приводит к

«файл не найден»

при выполнении.Я трижды проверил, что путь правильный.

Если я попробую это так:

   my @arguments = ("bash", $easyrsa_path,"build-client-full $clientname nopass");
   system(@arguments);

Bash вернет

"Неизвестная команда" build-client-полный тест nopass '. Запуск без команд для помощи использования. "

Ответы [ 2 ]

0 голосов
/ 27 мая 2018

Фон

Когда вы используете system(LIST), где LIST имеет более одного элемента, Perl не будет вызывать оболочку, а вместо этого напрямую вызывает программу, заданную первым элементомв LIST и используйте оставшуюся часть списка в качестве аргументов командной строки для передачи дословно , с интерполяцией no оболочкой, включая no splitаргументы в пробеле.

Итак, в вашем первом примере Perl запускает команду bash и передает строку "$easyrsa_path/easyrsa build-client-full $clientname nopass", буквально как один большой длинный аргумент, и во втором примереон запускает команду bash и передает два аргумента $easyrsa_path и "build-client-full $clientname nopass".Тем не менее, я предполагаю, что easyrsa нужны три аргумента в виде отдельных строк в своем списке аргументов, который оболочка обычно разделяет, но, поскольку оба ваших вызова к system не используют оболочку, она не работает.

systemexec) имеют четыре способа интерпретации своих аргументов согласно документации:

  1. Если вы передаете одну строку (включая LIST только с одним элементом), которая не содержит метасимволов оболочки, она разбивается на слова и передается непосредственно в execvp(3) (что означает, что она обходит оболочку), Предупреждение: Этот вызов легко спутать со следующим: один метасимвол вызовет вызов оболочки, что может быть опасно, особенно если непроверенные переменные интерполируются в командной строке.

  2. Если вы передаете одну строку (включая LIST только с одним элементом), которая содержит метасимволы оболочки, весь аргумент передается в командную оболочку системы для анализа.Обычно это /bin/sh -c на платформах Unix, но идея «оболочки по умолчанию» проблематична , и, конечно, нет гарантии, что это будет bash (хотя может be).

    Предупреждение: В этом вызове system вы получаете всю мощь оболочки, что также означает, что вы несете ответственность за правильное цитирование и выход из любой оболочкиметасимволы и / или пробелы.Я рекомендую вам только использовать эту форму, если вы явно хотите мощность оболочки, а в противном случае обычно лучше использовать один из следующих двух.

  3. Если в LIST имеется более одного аргумента, это вызывает execvp(3) с аргументами в LIST, что означает, что оболочки избегают.(Смотрите предостережения ниже в Windows.)

  4. Форма system {EXPR} LIST всегда запускает программу с именем EXPR и избегает оболочки, независимо от того, что находится вLIST.(Смотрите предостережения ниже в Windows.)

Последние два желательны, если вы хотите передать специальные символы, которые обычно интерпретируется оболочкой, и я бы действительно рекомендовал делать это,поскольку слепая передача пользовательского ввода в system может открыть дыру в безопасности - я написал более длинную статью об этом в PerlMonks .

Solutions

@ Бородин и @AnFi уже указывал: если вы просто правильно разделите элементы LIST, это должно сработать - похоже, вам не нужны какие-либо функции bash или какая-либо оболочка здесь.И не забудьте проверить на наличие ошибок!

system("$easyrsa_path/easyrsa","build-client-full",$clientname,"nopass") == 0
    or warn "system failed: \$? = $?";

Обратите внимание, что существуют хорошие модули, которые предоставляют альтернативы system и qx, мой модуль перехода обычноIPC::Run3.Эти модули очень полезны, если вы хотите захватить выходные данные из внешней команды.В этом случае IPC::System::Simple может быть проще, поскольку он обеспечивает замену для system с улучшенной обработкой ошибок, а также systemx, который всегда избегает оболочки.(Этот модуль - то, что autodie использует, когда вы говорите use autodie ':all';.)

use IPC::System::Simple qw/systemx/;
systemx("$easyrsa_path/easyrsa","build-client-full",$clientname,"nopass");

Обратите внимание, что если вы действительно хотели позвонить bash, вам нужно добавить опцию -c и сказать system("bash","-c","--","$easyrsa_path/easyrsa build-client-full $clientname nopass").Но, как я уже сказал выше, я настоятельно рекомендую против этого, поскольку, если $easyrsa_path или $clientname содержат метасимволы оболочки или вредоносный контент, у вас может возникнуть огромная проблема.

Windows

Windows сложнее, чем выше.В документации сказано, что единственный «надежный» способ избежать вызова оболочки - это форма system PROGRAM LIST, но в Windows аргументы командной строки передаются не в виде списка, а в виде одной большой строки, и это зависит от вызываемой команды.Не оболочка, чтобы интерпретировать эту строку, и разные команды могут делать это по-разному - см. также .(Хотя я слышал хорошие вещи о Win32::ShellQuote.)

Плюс, есть специальная форма system(1, @args), задокументированная в perlport .

0 голосов
/ 27 мая 2018

Если вы передаете несколько параметров в system, то каждый из них формирует отдельный параметр в командной строке.Таким образом, вы как будто ввели

easyrsa "build-client-full test nopass"

и правильно получаете сообщение об ошибке

Неизвестная команда 'build-client-full test nopass'

Вам также не нужно добавлять bash: Perl запустит оболочку для вас, если это необходимо

Вы можете передать всю команду на system

system($cmd)

иPerl передает его в оболочку для обработки, как если бы вы ввели ее в командной строке.Или вы можете правильно разделить параметры

system("$easyrsa_path/easyrsa", "build-client-full", $clientname, "nopass")

, что сделает вызов perl easyrsa напрямую, если только в команде нет вещей, для обработки которых требуется оболочка, например перенаправление вывода

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...