如何在 Makefile 目标中实现 $(<some-file) ?

How can I achieve $(<some-file) inside a Makefile target?

我正在尝试从 https://docs.gitlab.com/ee/api/lint.html#use-jq-to-create-and-process-yaml--json-payloads 执行 jq 管道 curl 命令,但在 make 文件上下文中。

我花了好几个小时尝试转义和尝试替代命令的每一个排列,但我无法让等效的工作。我在 makefile 之外没有问题。

我尝试用 "$$(<foo.yml)"$(shell cat foo.yml) 甚至 cat foo.yml | ... @- 替换 "$(<foo.yml)" 但没有成功。 shell cat 是我得到的最接近的,但是 cat 删除了 \n 字符,这使得我传递给 GitLab 的结果 JSON 返回时出现令人困惑的错误: {"valid":false,"errors":["(\u003cunknown\u003e): 在第 1 行第 12 列的上下文中不允许块序列条目"],"warnings":[],"status":"无效"}

我将字符串与 Makefile 上下文之外的工作原始版本进行了比较,唯一不同的是缺少 \n 字符。

请帮忙!谢谢。

编辑 根据要求,这里是 URL.

的额外详细信息

这是我试图移动到 Makefile 上下文中的命令。此命令直接从我的 bash 终端运行正常。

jq --null-input --arg yaml "$(<.gitlab-ci.yml)" '.content=$yaml' | curl "https://gitlab.com/api/v4/ci/lint?" --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $GITLAB_PERSONAL_ACCESS_TOKEN" --data @-

回复如下: {"valid":true,"errors":[],"warnings":[],"status":"valid"}

这是我的 Makefile 版本:

.PHONY: lint
make lint:
    jq --null-input '.content="$(shell cat "$(GITLAB_CI_FILE_PATH)")"' | curl --header "Content-Type: application/json" --header "PRIVATE-TOKEN: $(GITLAB_PERSONAL_ACCESS_TOKEN)" --data @- "https://gitlab.com/api/v4/ci/lint"

回复如下: {"valid":false,"errors":["(\u003cunknown\u003e): block sequence entries are not allowed in this context at line 1 column 12"],"warnings":[],"status":"invalid"}

我知道这是因为我的 makefile 版本不包含换行符。

这是输入的 YAML 文件:

include:
  - project: adamcunnington.info/MLG/common
    file: /cicd/.gitlab-ci-python.yml

如果您提供您要编写的完整规则,那将非常有帮助。

在 make 配方中使用 $(<foo.yml) 无效,因为 make 将以 $ 开头的所有内容都视为 make 变量,并在 运行 和 shell 之前扩展它.您需要转义您希望 shell 看到的所有 $,如 $$.

使用 $$(<foo.yml) 在某些系统上有效,但在其他系统上无效:POSIX 标准未定义该语法,因此 shell 提供 POSIX features 不会用它做任何事情。这是 bash shell 的增强语法。默认情况下,Make 总是运行 /bin/sh,所以如果你的 /bin/sh 真的是 bash,它可能会起作用。没有就没有。

使用 $(shell cat foo.yml) 无法工作,因为 make 的 shell 函数会在替换之前从输出中删除所有换行符。

由于我们看不到您的实际规则,因此无法真正建议最佳替代方案。有什么原因你不能使用简单的标准:

jq < foo.yml

?

预计到达时间

如前所述,您的 shell 是 bash。 Make always 默认使用 /bin/sh 作为 shell(想象一下如果 make 总是使用调用它的人正在使用的任何 shell 可移植性问题)。

如果您不知道如何重写您的 makefile 配方以使用标准 POSIX 语法,而是想使用 bash 特定的语法,您可以告诉 make 使用 bash 作为其 shell:

SHELL := /bin/bash

现在所有 bash 特有的魔法都将在您的食谱中发挥作用。当然,您的 makefile 将无法在没有 /bin/bash.

的系统上运行

jq 部分的更简单和更便携的重新表述将是

jq --null-input --rawfile yaml .gitlab-ci.yml '.content=$yaml'

在一个 Makefile 里面,显然是美元符号的两倍。

一个细微差别是 --rawfile 文件中的最后一个换行符也包含在内。

--rawfile 选项是在 jq 1.6 中引入的。