如何在Makefile脚本中对环境变量执行字符串替换?
在Makefile中处理字符串替换的正确方法
问题场景
你有如下Makefile脚本:
build: DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} -t ${DOCKER_REGISTRY}/strick:${IMAGE_BRANCH}-${IMAGE_TAG} -t ${DOCKER_REGISTRY}/strick:${IMAGE_BRANCH}-latest .
当${IMAGE_BRANCH}包含斜杠(如feature/a-b-c)时,Docker构建会失败——因为镜像标签不允许包含斜杠。你尝试通过shell命令替换斜杠为横杠,但写法有误,导致CLEANED_IMAGE_BRANCH为空,执行时报错:
❮❮❮ DOCKER_REGISTRY=docker IMAGE_BRANCH="a/b" IMAGE_TAG="lol" make build CLEANED_IMAGE_BRANCH= DOCKER_BUILDKIT=1 docker build --build-arg GITHUB_ACTOR= --build-arg GITHUB_TOKEN= -t docker/strick:-lol -t docker/strick:-latest . invalid argument "docker/strick:-lol" for "-t, --tag" flag: invalid reference format See 'docker build --help'. make: *** [build] Error 125
解决方法
方法一:使用Makefile原生字符串替换(推荐)
Makefile内置了变量替换语法,无需调用shell,效率更高且避免子shell问题。语法为$(变量:原字符=替换字符):
写法1:直接在命令中替换
build: DOCKER_BUILDKIT=1 docker build \ --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} \ --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} \ -t ${DOCKER_REGISTRY}/strick:$(IMAGE_BRANCH:/=-)-${IMAGE_TAG} \ -t ${DOCKER_REGISTRY}/strick:$(IMAGE_BRANCH:/=-)-latest .
写法2:提前定义清理后的变量
# 立即展开变量,解析Makefile时完成替换 CLEANED_IMAGE_BRANCH := $(IMAGE_BRANCH:/=-) build: DOCKER_BUILDKIT=1 docker build \ --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} \ --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} \ -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-${IMAGE_TAG} \ -t ${DOCKER_REGISTRY}/strick:${CLEANED_IMAGE_BRANCH}-latest .
方法二:通过Shell命令处理(需保证同进程执行)
如果必须用shell命令(比如复杂替换逻辑),要注意Makefile中每行缩进的命令都是单独的shell进程,变量无法跨进程共享。需要把变量定义和构建命令放在同一个进程中,用; \连接多行:
build: CLEANED_IMAGE_BRANCH=$$(echo ${IMAGE_BRANCH} | sed 's/\//-/g'); \ DOCKER_BUILDKIT=1 docker build \ --build-arg GITHUB_ACTOR=${GITHUB_ACTOR} \ --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} \ -t ${DOCKER_REGISTRY}/strick:$${CLEANED_IMAGE_BRANCH}-${IMAGE_TAG} \ -t ${DOCKER_REGISTRY}/strick:$${CLEANED_IMAGE_BRANCH}-latest .
注意要点:
- 用
$$转义成shell的$,避免被Makefile解析为自身变量 - 用
; \连接所有命令,确保它们在同一个shell进程中执行,这样CLEANED_IMAGE_BRANCH才能被后续命令读取
验证效果
执行测试命令:
DOCKER_REGISTRY=docker IMAGE_BRANCH="a/b" IMAGE_TAG="lol" make build
会生成合法的镜像标签:docker/strick:a-b-lol和docker/strick:a-b-latest,构建可以正常执行。
内容的提问来源于stack exchange,提问作者Paymahn Moghadasian
相关产品推荐
相关产品推荐

