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

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

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

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

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

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

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

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

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

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

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

Ответ 1

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

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

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

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

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

Вы должны абсолютно избегать создания команд оболочки путем объединения переменных. Это плохая идея, похожая на конкатенацию фрагментов 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, что означает, что он взят буквально, без расширения переменной или какой-либо другой формы интерпретации.

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

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

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, одинакова во всех этих примерах. После того, как оболочка выполнила синтаксический анализ командной строки, команда не может сказать, что и как было указано. Даже если бы захотел.

Ответ 3

РЕДАКТИРОВАТЬ: (В соответствии с комментариями:)

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

Ответ 4

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

вместо

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

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

Например:

template='.... %s'

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

Ответ 5

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

QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

Ответ 6

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

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

repo forall -c $myvar

Ответ 7

Это работает для вас?

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