Как использовать переменные внутри одинарных кавычек

11

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

command -p 'cluster="cl1"'

Чтобы автоматизировать это, я создал файл bash, используя $CLUSTERв качестве переменной. Как должна быть моя команда? Другими словами, что я должен поставить вместо cl1?

Обратите внимание: если я изменил указанную выше команду, она не будет принята. Например: command -p "cluster=cl1"не принято

Мохамад-Джаафар Нехме
источник
2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
mikeserv
Другая возможность (если вы предпочитаете хранить cliбез кавычек внутри CLUSTERпеременной):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij
Наконец-то я нашел правильный ответ. Спасибо @jimmij.
Мохамад-Джафар NEHME

Ответы:

8

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

CLUSTER=cl1; cluster=$CLUSTER command

... и установить среду для него при вызове.

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

  • "''''" - строка с мягкими кавычками может содержать любое количество жестких кавычек.
  • "\""- \обратная косая черта может экранировать "мягкую кавычку внутри "строки с мягкими кавычками.
    • В этом контексте \\обратная косая черта также экранирует себя, \$токен расширения и \nнамотки, как отмечено ниже, но в остальном трактуется буквально.
  • "${expand} and then some"- строка в мягких кавычках может содержать интерпретированное $расширение оболочки .
  • '"\'- 'строка с жесткими кавычками может содержать любой символ, кроме 'жестких кавычек.
  • \- обратная косая черта без кавычек будет экранирована от любого следующего символа для буквального толкования - даже от другой обратной косой черты - кроме \newline.
    • В \\nслучае ewline и \обратная косая черта, и \newline полностью удаляются из полученной интерпретированной команды.
  • ${parameter+expand "$parameter"}- кавычки, возникающие в результате расширения оболочки, почти никогда не служат маркерами-разделителями, за исключением нескольких особых случаев. Я не рискну описывать это здесь дальше.

Я считаю странным, что любое приложение будет интерпретировать кавычки в своих аргументах командной строки. Такая практика не имеет большого смысла в этом - по крайней мере для оболочек - основная цель цитаты, как правило, заключается в разграничении аргумента. При вызове, однако, аргументы всегда уже разграничены с \0NULсимволами и поэтому цитаты не могут служить много целей.

Даже оболочка обычно интерпретирует кавычки только в одном из своих аргументов вызова, когда она вызывается с помощью -cпереключателя, что означает, что ее первый операнд на самом деле является сценарием оболочки, который должен запускаться при вызове. Это случай дважды оцененного ввода.

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

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

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

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

Вы можете избежать "с помощью \обратной косой черты внутри "строки в кавычках.

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

Вы можете чередовать и объединять стили цитирования, чтобы получить желаемый конечный результат, как указано в примечаниях @jimmij выше .

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

Вы можете отключить как генерацию имени файла, так и $IFSразбиение - тем самым $expansionвообще избегая необходимости заключать в кавычки - и, таким образом, только заключать в кавычки. Это, вероятно, излишне.

Наконец, есть еще один тип кавычек, который можно использовать. Как я уже отмечал ранее, sh -c "$scriptlet"форма вызова оболочки часто используется для предоставления сценария оболочки в командной строке. Когда это $scriptletусложняется - например, когда кавычки должны содержать другие кавычки - часто может быть выгодно использовать здесь-документ и sh -sвместо этого - где оболочка специально проинструктирована назначать все последующие операнды позиционным параметрам, как это было бы в -cслучае и все же, чтобы взять его сценарий из stdin.

Если ваша команда должна интерпретировать кавычки таким образом, я бы посчитал, что лучше это сделать при вводе файла. Например:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

Если вы не заключаете в кавычки разделитель, <<here-documentтогда все его содержимое обрабатывается почти точно так же, как они были заключены в "мягкие кавычки, за исключением того, что "сами двойные кавычки не обрабатываются специально. И так, если мы запустим выше с cat:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... это печатает ...

cluster="cl1"
mikeserv
источник
1

Как написал mikeserv :

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

«Двойная кавычка» каждый литерал , который содержит пробелы / метасимволы и каждое расширение: "$var", "$(command "$var")", "${array[@]}", "a & b". Используйте 'single quotes'для кода или буквального $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. См.
Http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words

Жиль Квено
источник
Вы правы, спасибо. Но как насчет автоматизации? Предположим, я хочу прочитать CLUSTER? Я снова
застряну
@ Мой - автоматизация не имеет большого значения, хотя вам придется дезинфицировать переменную "символов - достаточно только первого и последнего. Настоящая проблема здесь заключается в том, что ваше приложение интерпретирует кавычки в аргументе arg. Интерпретация кавычки в аргументе почти никогда не является хорошей идеей, потому что кавычка должна быть только средством разграничения аргумента - и при вызове, что разграничение обрабатывается \0NULs в каждом случае. Возможно, есть лучший способ передать информацию, которую вы хотите, в приложение? Как command --'script=/path/to/some/file'или что-то?
mikeserv