Makefile中shell输入变量使用及跨shell命令变量传递问题
嗨,这个问题其实是Makefile里$(shell)命令的一个常见坑——每个$(shell)调用都会启动一个独立的子shell进程,它们之间的环境变量是完全隔离的。所以你在第一个$(shell)里定义的DOCKER_IMAGE_ID,到第二个$(shell)里就完全看不到啦。
你提到echo $$DOCKER_IMAGE_ID能工作,应该是把这条命令和变量定义放在了同一个$(shell)调用里吧?比如像这样:
TEST=$(shell DOCKER_IMAGE_ID=$$(docker build -q -t myimage .); echo $$DOCKER_IMAGE_ID)
这种情况下两条命令属于同一个子shell进程,变量自然能正常传递,但分成两个$(shell)调用就不行了。
下面给你几个可行的解决方案:
方案1:将命令合并到同一个$(shell)中
把镜像构建和容器运行的命令放在同一个$(shell)调用里,让它们共享同一个子shell环境:
OUT=$(shell DOCKER_IMAGE_ID=$$(docker build -q -t myimage .); docker run --rm $$DOCKER_IMAGE_ID)
这里的$$是用来转义Makefile里的$符号,让底层shell能正确识别$(docker build...)这个命令替换。
方案2:用Makefile变量存储镜像ID,再传递给后续$(shell)
先把镜像ID赋值给一个Makefile全局变量,然后在第二个$(shell)里直接引用这个Makefile变量:
DOCKER_IMAGE_ID=$(shell docker build -q -t myimage .) OUT=$(shell docker run --rm $(DOCKER_IMAGE_ID))
这种方式更清晰,也方便后续其他地方复用DOCKER_IMAGE_ID变量。需要注意的是,如果docker build执行失败,这个变量会是空值,你可以加一些判断逻辑避免后续命令出错。
方案3:导出Makefile变量到子shell环境
如果需要在多个独立的$(shell)调用里共享变量,可以用Makefile的export指令把变量导出到子shell的环境中:
DOCKER_IMAGE_ID=$(shell docker build -q -t myimage .) export DOCKER_IMAGE_ID OUT=$(shell docker run --rm $$DOCKER_IMAGE_ID)
这里export之后,子shell就能通过环境变量拿到DOCKER_IMAGE_ID,所以要用$$DOCKER_IMAGE_ID来转义引用这个shell环境变量。
一般来说,方案1和方案2是最常用的,根据你的实际场景选择就好啦。
内容来源于stack exchange

