make вычислить значение в правиле
Не получается вычислить значение в правиле и записать его в переменную.
Есть вот такое правило:
elastic-load-balancer:
$(info "running elastic load balancer of yandex cloud")
COMMAND_VAR=...
cd elb && terraform plan
cd elb && terraform apply -auto-approve -var="yandex_compute_instance_group_id=${COMMAND_VAR}"
Вместо многоточия мне требуется подставить cd instance_group && echo $(terraform output terraform_group_instance_id) и записать в переменную результат выполнения команды terraform output terraform_group_instance_id.
Затем эту переменную нужно подставить ниже, в коде. Как это сделать?
UPD
$(info "running elastic load balancer of yandex cloud" ${cd instance_group/ && terraform output terraform_group_instance_id})
Ответ не подставляет. Если выполнить команду, то получу строку
Ответы (3 шт):
В большинстве имплементаций make, включая GNU Make,
каждая команда выполняется в отдельном процессе, так что очевидно, что
переменные так работать не будут. Про вынос в скрипт я уже написал вам
в комментарии. Вот вариант с макросами для POSIX Make:
COMMAND_VAR = $$(echo foo)
elastic-load-balancer:
@ echo "running elastic load balancer of yandex cloud"
cd elb && terraform plan
cd elb && terraform apply -auto-approve\
-var="yandex_compute_instance_group_id=$(COMMAND_VAR)"
Дополню предыдущий ответ, для ограничения области видимости можно так же писать
elastic-load-balancer: COMMAND_VAR = $$(echo foo)
echo ${COMMAND_VAR}
...
Так же объявление можно вынести
elastic-load-balancer: COMMAND_VAR = $$(echo foo)
elastic-load-balancer:
echo ${COMMAND_VAR}
...
и так тоже будет корректно
elastic-load-balancer:
echo ${COMMAND_VAR}
...
...
elastic-load-balancer: COMMAND_VAR = $$(echo foo)
как уже отметили в другом ответе, по умолчанию для каждой строки рецепта запускается новый экземпляр оболочки. напомню терминологию, используемую для описания правила (rule):
цели : пререквизиты
рецепт
...
итак. можно пойти разными путями:
например, объединить присвоение переменной и те команды, в которых она нужна, в «непрерывную» строку (если строка заканчивается символом
\, то следующая за ней считается её непосредственным продолжением). т.е., заменить в рецепте:COMMAND_VAR=... cd elb && terraform plan cd elb && terraform apply -auto-approve -var="yandex_compute_instance_group_id=${COMMAND_VAR}"на что-нибудь вроде:
COMMAND_VAR=... && \ cd elb && terraform plan && \ terraform apply -auto-approve -var="yandex_compute_instance_group_id=${COMMAND_VAR}"обратите внимание: я убрал один вызов cd. он получается лишним.
- добавить в файл специальную цель
.ONESHELL. в результате оболочка будет вызываться однократно на один рецепт, а не на каждую строку в каждом рецепте. учтите, что, например, количество тех жеcdнадо будет сократить. но лучше, вероятно, будет изменить весь подход. так, чтобы он соответствовал основной парадигме программы make: отслеживанию зависимостей между файлами и выполнению рецепта (т.е., «обновлению» цели, она же — файл) только в том случае, если у цели обновился хотя бы один пререквизит (и пререквизиты — тоже файлы).
в частности, начать можно с того, что результат выполнения программы, который вы записываете в переменную, записывать в файл.
а этот файл уже поставить пререквизитом к другой цели, в рецепте которой у вас сейчас подставляется значение переменной, вместо чего можно читать информацию из файла.
и т.д. и т.п.
всё-таки дополню: да, конечно, часто используются цели, файлам не соотвтетствующие (т.н. «phony targets»). главная их «проблема» в том, что они «рвут» основную парадигму программы make: обычная цель может не требовать обновления (если пререквизиты старше цели), а вот «phony»-цель требует обновления (выполнения рецепта) всегда. и того же она требует ещё и от тех целей, у которых записана в пререквизиты.