Почему расширение переменной bash сохраняет кавычки?

12
> echo "hi"
hi
> VAR='echo "hi"'
> $VAR
"hi"

Почему вывод вышеприведенных команд отличается?

Похожая вещь происходит с одинарными кавычками:

> VAR="echo 'hi'"
> $VAR
> 'hi'
Кори Кляйн
источник
6
Пожалуйста, не заводите фрагменты исполняемого скрипта в переменные. В лучшем случае это сложно, и evalэто минное поле потенциальных дыр в безопасности, которые вы должны очень осторожно
пройти
@ jw013 Хороший вопрос и отличные статьи. Мне нравится цитата «Переменные содержат данные, функции содержат код». из первой ссылки, но для моего использования данные, которые передаются функции (в данном случае at), являются кодом. Какие-нибудь советы по безопасному способу организации / сбора кода, который будет дан at?
Кори Кляйн
atпринимает shсинтаксис в качестве входных данных. Таким образом, генерирование входных данных atозначает создание правильного shсинтаксиса с правильными кавычками из произвольного ввода, что не является тривиальным, поэтому я постараюсь избежать этого, если это вообще возможно. Было бы очень полезно, если бы вы могли немного подробнее рассказать о том, что вы пытаетесь достичь.
jw013
Извините, я не хотел отвлекаться на слишком много деталей, но то, что я делаю, не очень сложно, ИМО. Я создаю сценарий, который занимает «время» и «сообщение». Затем он запускается в atтечение заданного «времени» и говорит atвыполнить команду dzen2. dzen2принимает "сообщение" из стандартного ввода, а также использует некоторые другие статические параметры. Сложность в том, что мне нужно передать параметр «message» от пользователя в dzen2команду, но я на самом деле не запускаю dzen2сам, я говорю atэто делать.
Кори Кляйн
1
superuser.com/questions/360966/… || stackoverflow.com/questions/7454526/…
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件

Ответы:

16

Дополнительная пара цитат будет потребляться только на дополнительном шаге оценки. Например, принудительно eval:

bash-4.2$ VAR='echo "hi"'

bash-4.2$ $VAR
"hi"

bash-4.2$ eval $VAR
hi

Но, как правило, плохая идея помещать команды с параметрами в одну строку. Вместо этого используйте массив:

bash-4.2$ VAR=(echo "hi")

bash-4.2$ "${VAR[@]}"
hi
manatwork
источник
1
Также важно отметить, что кавычки оцениваются по-разному; двойные кавычки (") позволяют вычислять вложенную строку, одинарные кавычки (') печатают строку как литерал. Пример: "$(ls)"и '$(ls)'. Это причина, по которой кавычки появляются в исходных примерах вопросов.
Джозеф Керн,
Массив также является источником проблем. Код принадлежит функциям, данные - переменным. Представленный вами пример работает только потому, что кавычки удаляются в разбиении массива. А printf '<%s> ' "${VAR[@]}"покажет, что цитаты уже удалены. Если вы установите VAR так, VAR=(echo \"hi\")чтобы на самом деле были кавычки, та же проблема появится снова, $ ${VAR[@]}будет напечатано"hi"
9

Удаление кавычек происходит только в исходных словах ввода, а не в результате расширений. Кавычки, которые являются частью расширенных переменных, остаются нетронутыми.

jw013
источник
2

Если вы отступите немного назад, вы поймете, почему подстановка переменных должна сохранять кавычки.

Смысл кавычек в оболочке Unix / Linux / BSD состоит в том, чтобы объединить части строки, которые в противном случае были бы проанализированы как несколько строк. Поскольку по умолчанию оболочка использует пробел в качестве разделителя токенов, строка с пробелами (например, «один два три»), если она не заключена в кавычки или не экранирована каким-либо образом, будет проанализирована как 3 строки: «одна», «два» и «три».

Если программист хочет получить строку со значением некоторой переменной, интерполированной:

VAR=two
STRING="one $VAR three"

оболочка абсолютно не должна удалять кавычки: строка, содержащая пробелы, будет проанализирована как 3 меньшие строки.

Брюс Эдигер
источник