迭代 submake 的值

Iterating the values of a submake

我正在尝试自动执行我在 Makefile 中经常使用的一些命令,但我似乎无法找出正确的语法。

给定以下目标:

.PHONY: params-list
params-list:
    @aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name'

.PHONY: params-get
params-get:
    @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value

我试图调用 params-list,然后将结果输入 params-get。我最好的尝试是:

.PHONY: params
params:
    for param in $(MAKE) params-list; do \
        $(MAKE) params-get PARAM=$${param}; \
    done

但是显然不行。实现这一目标的正确方法是什么?

你可以做一个(长)target/recipe如下:

.PHONY: params-get
params-get:
    @for p in $$(aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name'); do \
        aws ssm get-parameter --name $$p --with-decryption | jq -c -r .Parameter.Value; \
     done

这假定您的参数中没有空格

------------编辑--------------

为了能够访问另一个配方中的参数,您可以创建一个规则来创建一个文件,其中包含一个配方中的文件列表,然后在另一个配方中访问该文件:

# note that in this case .params-list is actually the name of a file,
# but it is declared as phony to force it to be rebuilt every time.
.PHONY: .params-list
.params-list:
    aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name' > $@

.PHONY: params-get
params-get: .params-list
    @for param in $$(cat .params-list); do \
       aws ssm get-parameter --name $${param} --with-decryption | jq -c -r .Parameter.Value; \
     done;

一个提示是避开 shell 构造 make 构造。一步一步来。

对于get操作,我们为每个参数编码一个目标。因此,对于参数 p1(比方说),我们发明了一个目标 params-get<p1>。我们注意到在配方内部(即 shell 命令),$@ 将扩展为 params-get<p1>。因此 ${@:params-get<%>=%} 将扩展为 p1.

make 语法写出来:

.PHONY: params-get<p1>
params-get<p1>:
      @aws ssm get-parameter --name ${@:params-get<%>=%} --with-decryption | jq -c -r .Parameter.Value

我注意到,使用中间变量,我们可以获得与您之前的咒语完全相同的配方。

PARAM = ${@:params-get<%>=%}

.PHONY: params-get<p1>
params-get<p1>:
      @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value

如果我们有第二个参数 pa(比方说),那很容易添加:

PARAM = ${@:params-get<%>=%}

.PHONY: params-get<p1> params-get<pa>
params-get<p1> params-get<pa>:
      @aws ssm get-parameter --name ${PARAM} …

我希望你能看到一些样板出现在这里。

转向一些更动态生成的 make,而不是对每个参数进行硬编码,让我们将所有可能的参数放在一个名为 $PARAMS[=28= 的列表中]

PARAMS := p1 pa another
get-targets := ${PARAMS:%=params-get<%>}

PARAM = ${@:params-get<%>=%}

.PHONY: ${get-targets}
${get-targets}:
      @aws ssm get-parameter --name ${PARAM} …

.PHONY: params-get
params-get: ${get-targets}
      echo $@ Done 

我已经添加了您原来的 params-get 目标。现在所有的工作都由依赖完成。

  • 看不到 shell 循环。
  • 每个 aws ssm get-parameter 的退出代码由 make 检查。
  • 代码是并行安全的:make -j9 将运行 9 个并行作业,直到工作耗尽。如果你有 8 个 CPU 就好了。 (如果你的 make 不是并行安全的,那么它 broken 顺便说一下。)

我们现在很接近了。我们只需要确保 $PARAMS 设置为 ssm get-parameters-by-path.

的输出

类似于:

.PHONY: params-list
params-list:
    @aws ssm get-parameters-by-path --path /${SERVICE}/${ENV} | jq -c -r '.Parameters[] | .Name'

PARAMS := $(shell ${MAKE} params-list)
get-targets := ${PARAMS:%=params-get<%>}

PARAM = ${@:params-get<%>=%}

.PHONY: ${get-targets}
${get-targets}:
      @aws ssm get-parameter --name ${PARAM} --with-decryption | jq -c -r .Parameter.Value

.PHONY: params-get
params-get: ${get-targets}
      echo $@ Done 

绝对不喜欢使用 $(shell …),但这只是一个草图。