Вслед за: неожиданное поведение при подстановке команд оболочки
У меня есть команда, которая может принять огромный список аргументов, некоторые из которых могут законно содержать пробелы (и, возможно, другие вещи)
Я написал скрипт, который может генерировать эти аргументы для меня, с кавычками, но я должен скопировать и вставить вывод, например
./somecommand
<output on stdout with quoting>
./othercommand some_args <output from above>
Я пытался упростить это, просто делая
./othercommand $(./somecommand)
и столкнулся с неожиданным поведением, упомянутым в вопросе выше. Вопрос в том, может ли подстановка команд надежно использоваться для генерации аргументов, если для othercommand
некоторых аргументов требуется процитирование, а это нельзя изменить?
shell
arguments
command-substitution
user1207217
источник
источник
eval
их можно использовать, но обычно это не рекомендуется.xargs
это то, что нужно учитыватьsomecommand
будут проходить регулярный анализ оболочки:
) ... при условии , что характер будет надежно не быть на выходе.Ответы:
Если выходные данные правильно указаны для оболочки, и вы доверяете выходным данным , тогда вы можете запустить
eval
их.Предполагая, что у вас есть оболочка, которая поддерживает массивы, лучше всего использовать ее для хранения полученных аргументов.
Если
./gen_args.sh
выдает вывод, как'foo bar' '*' asdf
, то мы можем запуститьeval "args=( $(./gen_args.sh) )"
заполнить массивargs
с результатами. Это было бы три элементаfoo bar
,*
,asdf
.Мы можем использовать
"${args[@]}"
как обычно, чтобы расширить элементы массива индивидуально:(Обратите внимание, что кавычки
"${array[@]}"
распространяются на все элементы как отдельные аргументы без изменений. Без кавычек элементы массива могут быть разбиты на слова. См., Например, страницу «Массивы» в BashGuide .)Тем не менее ,
eval
он с радостью выполнит любые замены оболочки, поэтому$HOME
в выходных данных развернется ваш домашний каталог, а подстановка команд фактически запустит команду в запущенной оболочкеeval
. Выходные данные"$(date >&2)"
создадут один пустой элемент массива и выведут текущую дату на стандартный вывод. Это вызывает беспокойство, еслиgen_args.sh
данные из какого-либо ненадежного источника, например с другого хоста в сети, получают имена файлов, созданные другими пользователями. Вывод может включать произвольные команды. (Если быget_args.sh
он был вредоносным, ему не нужно ничего выводить, он мог бы просто запускать вредоносные команды напрямую.)Альтернативой кавычкам оболочки, которую трудно проанализировать без eval, было бы использование некоторого другого символа в качестве разделителя в выходных данных вашего скрипта. Вам нужно будет выбрать тот, который не нужен в реальных аргументах.
Давайте выберем
#
и получим вывод сценарияfoo bar#*#asdf
. Теперь мы можем использовать раскрытие команды без кавычек, чтобы разделить вывод команды на аргументы.Вам нужно будет установить
IFS
позже, если вы зависите от разбиения слов в другом месте скрипта (unset IFS
должно работать, чтобы сделать его по умолчанию), а также использовать,set +f
если вы хотите использовать глобирование позже.Если вы не используете Bash или другую оболочку с массивами, вы можете использовать позиционные параметры для этого. Замените
args=( $(...) )
наset -- $(./gen_args.sh)
и используйте"$@"
вместо"${args[@]}"
этого. (Здесь тоже нужны кавычки"$@"
, в противном случае позиционные параметры могут быть разбиты на слова.)источник
${args[@]}
- иначе у меня это не получилось"${array[@]}"
с"$@"
. Оба должны быть заключены в кавычки, иначе разделение слов разбивает элементы массива на части.Проблема в том, что как только ваш
somecommand
сценарий выводит параметры дляothercommand
, параметры становятся просто текстовыми и зависят от стандартного синтаксического анализа оболочки (зависит от того, что$IFS
происходит, и какие параметры оболочки действуют, чего вы в общем случае не сделаете быть под контролем).Вместо того,
somecommand
чтобы использовать для вывода параметров, было бы проще, безопаснее и надежнее использовать его для вызоваothercommand
.somecommand
Сценарий бы тогда скрипт - обертка вокругothercommand
вместо какого - то хелперов сценария , который вы должны помнить , чтобы позвонить в каком - то особом образе , как часть командной строкиotherscript
. Сценарии обертки - это очень распространенный способ предоставления инструмента, который просто вызывает какой-то другой подобный инструмент с другим набором параметров (просто проверьте,file
какие команды в/usr/bin
действительности являются оболочками сценариев оболочки).В
bash
,ksh
илиzsh
, вы можете легко скрипт - обертка , которая использует массив для хранения индивидуальных вариантов ,othercommand
как так:Затем вызовите
othercommand
(все еще внутри сценария оболочки):Расширение
"${options[@]}"
будет гарантировать, что каждый элементoptions
массива будет заключен в кавычки и представленothercommand
как отдельные аргументы.Пользователь обертке бы не обращая внимания на то , что это на самом деле вызывающему
othercommand
, то , что бы не быть правдой , если сценарий вместо этого просто генерируется параметры командной строки дляothercommand
как выход.В
/bin/sh
, используйте$@
для хранения параметров:(
set
Команда используется для установки позиционных параметров$1
,$2
, и$3
т.д. Это то , что делает массив$@
в стандартном POSIX оболочки. Первоначально--
это сигнализировать ,set
что нет , данные опций, только аргументов.--
Это действительно необходимо только , если первое значение оказывается чем-то, начинающимся с-
).Обратите внимание, что это двойные кавычки,
$@
и${options[@]}
это гарантирует, что элементы не разделяются на слова по отдельности (и имя файла сглаживается).источник
set --
?Если
somecommand
выходные данные имеют надежный синтаксис оболочки, вы можете использоватьeval
:Но вы должны быть уверены, что выходные данные имеют правильные кавычки и т. Д., В противном случае вы можете также запустить команды вне скрипта:
Обратите внимание, что
echo rm bar baz test.sh
он не был передан в скрипт (из-за;
) и был запущен как отдельная команда. Я добавил|
вокруг,$var
чтобы выделить это.Как правило, если вы не можете полностью доверять выводу
somecommand
, невозможно надежно использовать его вывод для построения командной строки.источник