Фон
Когда вы используете 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
не используют оболочку, она не работает.
system
(и exec
) имеют четыре способа интерпретации своих аргументов согласно документации:
Если вы передаете одну строку (включая LIST
только с одним элементом), которая не содержит метасимволов оболочки, она разбивается на слова и передается непосредственно в execvp(3)
(что означает, что она обходит оболочку), Предупреждение: Этот вызов легко спутать со следующим: один метасимвол вызовет вызов оболочки, что может быть опасно, особенно если непроверенные переменные интерполируются в командной строке.
Если вы передаете одну строку (включая LIST
только с одним элементом), которая содержит метасимволы оболочки, весь аргумент передается в командную оболочку системы для анализа.Обычно это /bin/sh -c
на платформах Unix, но идея «оболочки по умолчанию» проблематична , и, конечно, нет гарантии, что это будет bash
(хотя может be).
Предупреждение: В этом вызове system
вы получаете всю мощь оболочки, что также означает, что вы несете ответственность за правильное цитирование и выход из любой оболочкиметасимволы и / или пробелы.Я рекомендую вам только использовать эту форму, если вы явно хотите мощность оболочки, а в противном случае обычно лучше использовать один из следующих двух.
Если в LIST
имеется более одного аргумента, это вызывает execvp(3)
с аргументами в LIST
, что означает, что оболочки избегают.(Смотрите предостережения ниже в Windows.)
Форма 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 .