it-swarm.com.ru

Расширение переменной внутри одинарных кавычек в команде в Bash

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

например repo forall -c '....$variable'

В этом формате $ экранируется, а переменная не раскрывается.

Я попробовал следующие варианты, но они были отклонены:

repo forall -c '...."$variable" '

repo forall -c " '....$variable' "

" repo forall -c '....$variable' "

repo forall -c "'" ....$variable "'"

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

Пожалуйста, скажите мне, где я иду не так.

269
Rachit

Внутри одинарных кавычек все сохранилось буквально, без исключения.

Это означает, что вы должны закрыть кавычки, вставить что-то, а затем снова войти.

'before'"$variable"'after'
'before'"'"'after'
'before'\''after'

Как вы можете убедиться, каждая из приведенных выше строк является одним словом в оболочку. Конкатенация строк выполняется просто путем сопоставления. Кавычки (одинарные или двойные, в зависимости от ситуации) используются для отключения интерпретации различных специальных символов, таких как пробелы, $, ;... Хороший учебник по цитированию см. В ответе Марка Рида. Также актуально: Какие символы нужно экранировать в bash?

Не объединять строки, интерпретируемые оболочкой

Вы должны абсолютно избегать создания команд Shell путем объединения переменных. Это плохая идея, похожая на конкатенацию фрагментов SQL (инъекция SQL!).

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

Например, следующее очень небезопасно. НЕ ДЕЛАЙТЕ ЭТОГО

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

Если содержимое $myvar не заслуживает доверия, вот эксплойт:

myvar='foo"; echo "you were hacked'

Вместо приведенного выше вызова используйте позиционные аргументы. Следующий вызов лучше - он не пригоден для использования:

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

Обратите внимание на использование одиночных тиков в присваивании script, что означает, что оно взято буквально, без расширения переменных или любой другой формы интерпретации.

459
Jo So

Команде repo не важно, какие цитаты она получает. Если вам нужно расширение параметров, используйте двойные кавычки. Если это означает, что вам приходится сталкиваться с большим количеством вещей, используйте большую часть одинарных кавычек, а затем вырывайтесь из них и переходите в двойные числа для той части, где вам нужно расширение.

repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'

Объяснение следует, если вам интересно.

Когда вы запускаете команду из командной консоли, то эта команда получает в качестве аргументов массив строк с нулевым символом в конце. Эти строки могут содержать абсолютно любой ненулевой символ.

Но когда Shell создает этот массив строк из командной строки, он интерпретирует некоторые символы специально; это сделано для того, чтобы упростить (возможно, сделать) команды для ввода. Например, пробелы обычно указывают границу между строками в массиве; по этой причине отдельные аргументы иногда называют «словами». Но, тем не менее, аргумент может содержать пробелы; вам просто нужен какой-то способ сказать Shell, что вы хотите.

Вы можете использовать обратную косую черту перед любым символом (включая пробел или другую обратную косую черту), чтобы сказать Shell, чтобы она трактовала этот символ буквально. Но пока вы можете сделать что-то вроде этого:

echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

... это может стать утомительным. Таким образом, Shell предлагает альтернативу: кавычки. Они бывают двух основных разновидностей.

Двойные кавычки называются «группирующими кавычками». Они предотвращают расширение подстановочных знаков и псевдонимов, но в основном они предназначены для включения пробелов в Word. Другие вещи, такие как расширение параметров и команд (такие вещи, которые $), все еще происходят. И, конечно, если вы хотите, чтобы буквальные двойные кавычки были в двойных кавычках, вы должны использовать обратную косую черту:

echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

Одиночные кавычки более драконовские. Все между ними воспринимается буквально, включая обратную косую черту. Нет абсолютно никакого способа получить буквальную одинарную кавычку внутри одинарных кавычек. 

К счастью, кавычки в Shell не являются разделителями Word; сами по себе они не заканчивают Слово. Вы можете входить и выходить из цитат (или между цитатами разных типов) в пределах одного и того же Слова, чтобы получить желаемый результат: 

echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

Так что это проще - намного меньше обратной косой черты, хотя последовательность «закрывающая одинарная кавычка», «обратная косая черта», буквальная одинарная кавычка, открытая одинарная кавычка требует некоторого привыкания.

Современные оболочки добавили еще один стиль цитирования, не указанный в стандарте POSIX, в котором перед одинарной кавычкой стоит начальный знак доллара. Строки, заключенные в кавычки, следуют соглашениям, аналогичным строковым литералам в языке программирования ANSI C, и поэтому их иногда называют «строки ANSI», а пару $'...' «кавычки ANSI». Внутри таких строк приведенный выше совет о том, что обратная косая черта воспринимается буквально, больше не применяется. Вместо этого они снова становятся особенными - вы можете не только включить буквальную одинарную кавычку или обратную косую черту, добавив к ней обратную косую черту, но и оболочка также расширяет экранирование символов ANSI C (например, \n для новой строки, \t для табуляции и \xHH для символ с шестнадцатеричным кодом HH). В противном случае, однако, они ведут себя как строки в одинарных кавычках: подстановка параметров или команд не происходит:

echo $'"Thank you.  That\'ll be $4.96, please," said the cashier'

Важно отметить, что единственная строка, полученная в качестве аргумента команды echo, является абсолютно одинаковой во всех этих примерах. После того как командная строка завершит синтаксический анализ командной строки, для запускаемой команды не будет возможности сообщить, что и как было указано. Даже если бы захотел.

76
Mark Reed

Правка: (Согласно комментариям в вопросе :)

Я изучал это с тех пор. Мне повезло, что у меня было репо. Тем не менее, мне не ясно, нужно ли вам принудительно заключать команды в одинарные кавычки. Я посмотрел в синтаксис репо, и я не думаю, что вам нужно. Вы можете использовать двойные кавычки вокруг своей команды, а затем использовать любые одинарные и двойные кавычки, которые вам нужны, если вы избегаете двойных.

2
Kevin Remo

Вот что сработало для меня -

QUOTE="'"
Hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"
1
Manmohan

просто используйте printf

вместо 

repo forall -c '....$variable'

используйте printf для замены токена переменной на расширенную переменную.

Например:

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")
0
AndrewD

Переменные могут содержать одинарные кавычки.

myvar=\'....$variable\'

repo forall -c $myvar
0
user3734617