我有以下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似乎没有得到正确的论点感到非常困惑。我敢肯定这与转义参数有关,但我一生都看不到。
答案 0 :(得分:0)
我发现可以通过在命令中添加“ shell”来解决此问题:
$(eval MY_IP=$(shell kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'))
答案 1 :(得分:0)
您可能会错过的是eval
参数是由make扩展的。因此,在:
$(eval MY_IP=$(kubectl describe service hello-node -n default | grep "LoadBalancer Ingress:" | awk '{print $$3}'))
$(kubectl describe...)
被make扩展为空字符串(除非您有一个名为kubectl describe...
的make变量,这不太可能)。 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 }'`
(除非您有一个名为3
的make变量)。这就是传递给外壳的内容,从而导致您看到的内容。改用$$$$3
,它应该可以按预期工作...除了未为make变量MY_IP
分配所需的值之外。
您注意到shell
函数可以解决所有这些问题,但最终会带来可怕的混合:shell命令,由make通过shell
函数求值,其结果分配给make变量多亏了eval
make函数,在食谱的中间,这是一列shell命令。我不知道您想做什么,但是必须有一些简单的方法。
例如,如果使用make变量只是因为无法将Shell变量从配方的一行传递到下一行(正常情况下,它们是由两个独立的Shell调用执行的),则可以将配方减少为一行(但连续; \
行以提高可读性):
deploy.runtime:
@MY_IP=`kubectl describe... | awk '{print $$3}'`; \
echo IP: $$MY_IP
此处,MY_IP
是一个shell变量,由于它是同一配方行的一部分,因此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时不会立即展开并执行shell命令。仅当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)
如果您有兴趣,请阅读his post about this。作为练习,您需要多少$
个awk
命令才能使用。