Используйте Bash массивы для достижения желаемого поведения, не прибегая к очень опасным (см. Ниже) eval
и bash -c
.
Использование массивов:
declare -a CMD=(echo --test-arg \"Hello\ there\ friend\")
set -x
echo "${CMD[@]}"
"${CMD[@]}"
выводит:
+ echo echo --test-arg '"Hello there friend"'
echo --test-arg "Hello there friend"
+ echo --test-arg '"Hello there friend"'
--test-arg "Hello there friend"
Будьте внимательны, чтобы ваш вызов массива был заключен в двойные кавычки;в противном случае Bash пытается выполнить ту же самую «минимальную безопасность», экранируя специальные символы:
declare -a CMD=(echo --test-arg \"Hello\ there\ friend\")
set -x
echo "${CMD[@]}"
${CMD[@]}
выводит:
+ echo echo --test-arg '"Hello there friend"'
echo --test-arg "Hello there friend"
+ echo --test-arg '"Hello' there 'friend"'
--test-arg "Hello there friend"
ASIDE: почему eval
опасен?
eval
безопасен только в том случае, если вы можете гарантировать, что каждый переданный ему ввод не изменит неожиданно способ работы команды в eval
.
Пример : AsПолностью надуманный пример, скажем, у нас есть скрипт, который выполняется как часть нашего процесса автоматического развертывания кода.Сценарий сортирует некоторые входные данные (в данном случае три строки текста с жестким кодом) и выводит отсортированный текст в файл, имя которого основано на имени текущего каталога.Подобно исходному вопросу SO, поставленному здесь, мы хотим динамически построить параметр --output=
, переданный для сортировки, но мы должны (не так ли) на самом деле полагаться на eval
из-за функции автоматического цитирования в Bash "safety".
echo $'3\n2\n1' | eval sort -n --output="$(pwd | sed 's:.*/::')".txt
Запуск этого сценария в каталоге /usr/local/deploy/project1/
приводит к созданию нового файла в /usr/local/deploy/project1/project1.txt
.
Так или иначе, если бы пользователь создавал подкаталог проекта с именем owned.txt; touch hahaha.txt; echo
Сценарий фактически запускает следующую серию команд:
echo $'3\n2\n1'
sort -n --output=owned.txt; touch hahaha.txt; echo .txt
Как видите, это совсем не то, что мы хотим.Но вы можете спросить, в этом надуманном примере, не маловероятно ли, что пользователь может создать каталог проекта owned.txt; touch hahaha.txt; echo
, и если они могли, разве мы уже не в беде?
Может быть, нокак насчет сценария, в котором скрипт анализирует не текущее имя каталога, а имя удаленной ветви репозитория git
с исходным кодом?Если вы не планируете проявлять предельную осторожность в отношении ограничения или дезинфекции каждого контролируемого пользователем артефакта, чье имя, идентификатор или другие данные используются вашим сценарием, держитесь подальше от eval
.