Должен ли я избегать аргументов оболочки в Perl?
При использовании system() вызовов в Perl, вам нужно избежать аргументов оболочки или это делается автоматически?
Аргументы будут введены пользователем, поэтому я хочу убедиться, что это невозможно использовать.
Ответы
Ответ 1
Если вы используете system $cmd, @args
, а не system "$cmd @args"
(массив, а не строку), вам не нужно избегать аргументов, потому что не вызывается оболочка (см. system). system {$cmd} $cmd, @args
не будет вызывать оболочку, даже если $cmd содержит метасимволы, а @args пуст (это документировано как часть exec). Если аргументы поступают от ввода пользователем (или другого ненадежного источника), вы все равно захотите их разблокировать. См. -T
в perlrun docs и perlsec.
Если вам нужно прочитать вывод или отправить ввод в команду, qx
и readpipe
не имеют эквивалента. Вместо этого используйте open my $output, "-|", $cmd, @args
или open my $input, "|-", $cmd, @args
, хотя это не переносимо, поскольку для этого требуется реальный fork
, что означает только Unix... Я думаю. Возможно, он будет работать на Windows с его симулированной вилкой. Лучший вариант - это что-то вроде IPC:: Run, который также будет обрабатывать случаи команд трубопровода для других команд, которые не имеют ни multi-arg форма системы или форма 4 arg формы будут обрабатываться.
Ответ 2
В Windows ситуация немного неприятнее. В принципе, все программы Win32 получают одну длинную строку командной строки - оболочка (обычно cmd.exe
) может сначала выполнить некоторую интерпретацию, удалив, например, перенаправления <
и >
, но она не разделяет ее на границах слов для программы. Каждая программа должна выполнять этот синтаксический анализ (если они того пожелают - некоторые программы не беспокоят). В программах на C и С++ подпрограммы, предоставленные библиотеками времени выполнения, поставляемыми с инструментальной цепочкой компилятора, обычно выполняют этот шаг синтаксического анализа до вызова main()
.
Проблема в том, что в целом вы не знаете, как данная программа будет анализировать свою командную строку. Многие программы скомпилированы с некоторой версией MSVС++, чьи правила
Таким образом, самый безопасный подход для экранирования аргументов в Windows:
Вывести аргументы в соответствии с логикой разбора командной строки программы, которую вы вызываете. (Надеюсь, вы знаете, что такое логика, а если нет, попробуйте несколько примеров и догадайтесь.)
Присоединяем экранированные аргументы с пробелами.
Префикс каждого не-алфавитно-цифрового символа результирующей строки с ^
.
Добавить любые перенаправления или другие обманы оболочки (например, объединение команд с &&
).
Запустите команду с помощью system()
или backticks.
Ответ 3
sub esc_chars {
# will change, for example, a!!a to a\!\!a
@_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;
return @_;
}
http://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html
Ответ 4
Если вы используете систему "$ cmd @args" (строка), вам нужно избежать аргументов, потому что вызывается оболочка.
К счастью, для строк с двойными кавычками требуется только четыре символа:
" - double quote
$ - dollar
@ - at symbol
\ - backslash
Ответ 5
Ответы на ваш вопрос были очень полезными. В конце я последовал за советом @runrig, но затем использовал команду open3() основного модуля, чтобы я мог захватить вывод из STDERR, а также STDOUT.
Для примера кода open3(), используемого с решением @runrig, см. мой родственный вопрос и ответ:
Вызов системных команд с Perl