Зачем мне нужно «\ $$ (переменная)» вместо «$$ (переменная)», чтобы получить «$ (переменная)»? - PullRequest
0 голосов
/ 17 марта 2020
new_contents = "\$$(cooly)"

all:
    mkdir -p subdir
    echo $(new_contents) | sed -e 's/^ //' > subdir/makefile
    @echo "---MAKEFILE CONTENTS---"
    @cd subdir && cat makefile
    @echo "---END MAKEFILE CONTENTS---"
    #cd subdir && $(MAKE)

# Note that variables and exports. They are set/affected globally.
cooly = "The subdirectory can see me!"
export cooly
# This would nullify the line above: unexport cooly

clean:
    rm -rf subdir

Мне нужна строка "$(cooly)", а не значение переменной.

Я пробовал несколько комбинаций:

  1. new_contents = "$(cooly)", дает значение переменной, The subdirectory can see me!
  2. new_contents = "$$", дает $
  3. new_contents = "\$(cooly)", дает Syntax error: Unterminated quoted string ошибка

Почему new_contents = "$$(cooly)" не дает "$(cooly)" но ничего не получается?

"$$" -> "$", так почему бы не "$$(cooly)" ---> "$(cooly)"?

1 Ответ

3 голосов
/ 17 марта 2020

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

Make передает строки рецептов в оболочку практически дословно: существует только один специальный символ (не считая обратную косую черту / символы новой строки в конце) и это $. Если make видит $, он попытается расширить его как ссылку на переменную. Чтобы избежать этого, вы должны экранировать его как $$, чтобы скрыть его от make.

Итак, давайте посмотрим на ваш make-файл:

cooly = "The subdirectory can see me!"

echo $(new_contents) ...

Если new_contents равен "$(cooly)", make видит $(cooly) как ссылку на переменную и раскрывает ее еще до того, как она вызовет оболочку. Итак, сначала make расширяет $(new_contents) до "$(cooly)", затем расширяет его до ""The subdirectory can see me!"" (потому что кавычки находятся в обеих переменных, и кавычки не являются специальными для создания: они так же, как и любой другой символ, такой как a или b). Результатом будет:

echo ""The subdirectory can see me!""

Оболочка будет подбрасывать кавычки, поскольку они не активны, и выводить это значение (в канал).

Если new_contents равно "\$(cooly)", это backsla sh ничего не значит сделать. Как и в кавычках, обратные косые черты (если они не находятся в конце строки) не являются специальными для создания. Так что make расширяется так же, как и раньше, но на этот раз команда, которую он передает оболочке, такова: обратные слеши

echo "\"The subdirectory can see me!""

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

Если new_contents равно "$$(cooly)", make не раскрывает переменную, она передается в оболочку следующим образом:

echo "$(cooly)"

Однако $ равно также специально для оболочки. Помещение в двойные кавычки не мешает оболочке пытаться ее расширить. Это говорит оболочке выполнить команду cooly и заменить вывод. Почти наверняка нет команды с именем cooly, и поэтому вы получите сообщение об ошибке в stderr (возможно, вы этого не заметили), и оболочка ничего не заменит, потому что ничего не печатает в stdout.

Если new_contents равен "\$$(cooly)", то make не будет расширяться и запустит следующую команду оболочки:

echo "\$(cooly)"

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

Вот несколько советов:

Во-первых, не включайте кавычки в ваши переменные make (если переменная не содержит всю команду оболочки) и вам нужны цитаты внутри него). Make не заботится о кавычках, а встраивание их в переменные затрудняет рассуждение о том, что увидит оболочка.

Включайте только цитаты в рецепт.

Во-вторых, помните, что Так как make не заботится о кавычках, он не имеет такого же поведения, как одиночные и двойные кавычки оболочки WRT. Вы можете использовать одинарные кавычки вокруг переменных make, чтобы уменьшить необходимость экранирования объектов из оболочки, не скрывая их от make.

Итак, я бы написал так:

new_contents = $$(cooly)

cooly = The subdirectory can see me!

all:
        mkdir -p subdir
        echo '$(new_contents)' | sed -e 's/^ //' > subdir/makefile
          ...

Кстати, это Никогда не стоит добавлять @ значений в ваш make-файл, пока он не будет полностью готов и работает. Просмотр выходных данных make print (что и отправляется в оболочку) очень помогает выяснить, верны ли ваши рецепты, и связана ли проблема с вашими make-конструкциями или shell-конструкциями.

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