Как установить переменные в make из команд, содержащих каналы и переменные - PullRequest
0 голосов
/ 24 июня 2019

У меня есть следующий файл make:

deploy.runtime:
    kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'
    $(eval MY_IP=$(kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'))
    @echo IP: $(MY_IP)

Когда я запускаю это, я получаю вывод:

35.198.222.110
IP: 

Похоже, что настраиваемая переменная MY_IP не установлена.Я также попытался запустить его с обратными галочками, как это:

$(eval MY_IP=`kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'`)

, что дает мне вывод:

IP: LoadBalancer Ingress: 35.198.222.110

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

Ответы [ 2 ]

0 голосов
/ 27 июня 2019

Что вы, вероятно, пропустили, так это то, что параметр eval расширяется командой make. Итак, в:

$(eval MY_IP=$(kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'))

$(kubectl describe...) расширяется make как пустая строка (если у вас нет переменной make с именем kubectl describe..., что маловероятно). Таким образом, функция eval присваивает пустую строку переменной make MY_IP. Это не происходит с обратными тиками, но здесь вы столкнулись с другой проблемой: назначена переменная MY_IP:

`kubectl describe... | awk '{print $3}'`

не результат его оценки оболочкой. Обратите внимание, что $$3 был преобразован в $3 командой make при расширении параметра eval. И это при выполнении:

echo IP: $(MY_IP)

, который make расширяет (рекурсивно) рецепт, который становится, шаг за шагом:

echo IP: `kubectl describe... | awk '{print $3}'`

и затем:

echo IP: `kubectl describe... | awk '{print }'`

(если у вас нет переменной make с именем 3). Это то, что передается в оболочку, что приводит к тому, что вы видите. Вместо этого используйте $$$$3, и он должен работать так, как вы ожидаете ... за исключением того, что переменной make MY_IP не присвоено требуемое значение.

Функция shell, как вы заметили, решает все это, но в итоге получается ужасная смесь: команда оболочки, вычисляемая make с помощью функции shell, ее результат присваивается переменной make благодаря eval функция make, в середине рецепта которой находится список команд оболочки. Я не знаю, что вы хотите сделать, но должно быть что-то попроще.

Например, если вы использовали переменную make только потому, что не могли передать переменную оболочки из одной строки вашего рецепта в другую (обычно они выполняются двумя независимыми вызовами оболочки), вы можете уменьшить свой рецепт до одна строка (но с ; \ продолжением строки для лучшей читаемости):

deploy.runtime:
    @MY_IP=`kubectl describe... | awk '{print $$3}'`; \
    echo IP: $$MY_IP

Здесь MY_IP - это переменная оболочки, и она все еще доступна команде echo, поскольку она является частью той же строки рецепта. Обратите внимание на двойной знак $ в $$3 и $$MY_IP для выхода из первого расширения командой make.

Если вместо этого вы действительно хотите использовать переменную make, вы можете назначить ее как обычную переменную make (с помощью обратных тиков или функции shell, по вашему желанию):

MY_IP = `kubectl describe... | awk '{print $$3}'`

deploy.runtime:
    @echo IP: $(MY_IP)

или

MY_IP = $(shell kubectl describe... | awk '{print $$3}')

deploy.runtime:
    @echo IP: $(MY_IP)

Важное примечание об этом последнем решении:

Назначение MY_IP = ... является рекурсивным (отложенным) назначением вместо простого (немедленного) присвоения MY_IP := .... Это означает, что команда оболочки не раскрывается и выполняется сразу же после вызова make. Только для make требуется значение MY_IP. Таким образом, если рецепт deploy.runtime является единственным местом, где есть ссылка на значение MY_IP, то kubectl... будет выполняться только при выполнении этого рецепта. Например, если у вас есть другая цель clean, рецепт которой не использует значение MY_IP, и если вы вызываете make clean, kubectl... не будет выполняться вообще. Недостатком является то, что если у вас есть несколько мест, где make нуждается в своем значении, kubectl... будет выполняться несколько раз.

Если вы используете простое назначение, вместо:

MY_IP := $(shell kubectl describe... | awk '{print $$3}')

команда kubectl будет выполняться только один раз, но будет выполняться каждый раз, когда вы вызываете make, даже если ее значение не требуется.

В случае, если это проблема, Mad Scientist имеет очень хороший трюк для объединения плюсов и минусов рекурсивных и простых заданий:

MY_IP = $(eval MY_IP := $$(shell kubectl...))$(MY_IP)

Если вам интересно, прочитайте его пост об этом . Сколько $ вам потребуется для команды awk, оставлено в качестве упражнения ...

0 голосов
/ 24 июня 2019

Я обнаружил, что могу это исправить, добавив в команду 'shell':

$(eval MY_IP=$(shell kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...