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

257

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

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

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

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

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

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

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

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

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

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

  • 21
    repo forall -c ' ...before... '"$variable"' ...after...'
  • 2
    @nm сделай ответ
Показать ещё 14 комментариев
Теги:
variables
quotes

6 ответов

403
Лучший ответ

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

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

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

  • 0
    @ Jo.SO, это не сработает. потому что команда репо будет принимать только параметры, пока не закроются первые кавычки. Все, что после этого будет проигнорировано для репо и сгенерирует еще одну ошибку.
  • 6
    @Rachit - оболочка не работает так. "some"thing' like'this это все одно слово в оболочке. Кавычки ничего не прекращаются, насколько синтаксический обеспокоен, и нет никакого способа для команды под названием оболочки , чтобы сказать , что было процитировано как.
Показать ещё 4 комментария
78

Команда 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". Внутри таких строк приведенный выше совет о обратных косых чертах буквально больше не применяется. Вместо этого они становятся особенными снова - вы можете не только включать буквенную одинарную кавычку или обратную косую черту, добавляя к ней обратную косую черту, но оболочка также расширяет escape-символы символов ANSI C (например, \n для новой строки, \t для вкладки и \xHH для символа с шестнадцатеричным кодом HH). В противном случае, они ведут себя как строки с одним кавычком: нет замены параметров или команд:

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

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

  • 2
    Да. Теперь я понимаю. Работает отлично. Большое спасибо за вашу помощь!
  • 6
    Этот ответ был потрясающим.
Показать ещё 3 комментария
2

Ниже приводится то, что сработало для меня -

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

  • 2
    Я надеюсь, что TBL_HDFS_DIR_PATH не предоставлен пользователем, кстати, это позволит сделать хороший SQL инъекцию ...
  • 0
    Помещение QUOTE в отдельную переменную совершенно излишне; одинарные кавычки внутри двойных кавычек являются обычным символом. (Кроме того, не используйте верхний регистр для ваших личных переменных.)
2

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

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

  • 0
    Спасибо Кевину за вашу помощь.
1

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

eval repo forall -c '....$variable'
  • 4
    Это для вас? На этот вопрос уже пять лет, и на него уже есть некоторые ответы, даже принятые ...
0

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

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

repo forall -c $myvar
  • 0
    Они могут, но это не правильный способ сделать это - вы все равно должны "$myvar" в двойных кавычках.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню