Должен ли я избегать аргументов оболочки в 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.

Ответ 4

Если вы используете систему "$ cmd @args" (строка), вам нужно избежать аргументов, потому что вызывается оболочка.

К счастью, для строк с двойными кавычками требуется только четыре символа:

"    - double quote
$    - dollar
@    - at symbol
\    - backslash

Ответ 5

Ответы на ваш вопрос были очень полезными. В конце я последовал за советом @runrig, но затем использовал команду open3() основного модуля, чтобы я мог захватить вывод из STDERR, а также STDOUT.

Для примера кода open3(), используемого с решением @runrig, см. мой родственный вопрос и ответ:
Вызов системных команд с Perl