Makefile遍历子文件夹批量构建Docker镜像时命令展开异常问题
批量构建Docker镜像的Makefile问题解决
问题描述
我有一个包含未知数量子文件夹的父文件夹,每个子文件夹中都包含一个Dockerfile。我希望编写一条Makefile命令,批量构建以子文件夹名称命名并对应打标签的镜像。
我先做了简单测试:
build.all.images: for f in $(find $(image_folder) -type d -maxdepth 1 -mindepth 1 -exec basename {} \;); do echo $${f}; done
当我将image_folder的值硬编码后单独执行find命令时,子文件夹被成功列出。但运行make命令时,仅得到如下输出:
for f in ; do echo ${f}; done
我还尝试使用ls命令结合tr、cut来获取子文件夹列表,但结果相同:
build.all.images: for f in $(ls -l $(image_folder) | grep '^d' | tr -s ' ' | cut -d ' ' -f 9); do echo $${f}; done
错误原因
问题出在Make的变量/函数展开时机:
Make会在执行shell命令之前,先解析所有$(...)语法。你写的$(find ...)和$(ls ...)会被Make当成自己的函数调用,但Make并没有内置find或ls函数,所以解析后返回空字符串,最终shell执行的就是空循环。
解决方案
有两种常用的修复方式:
方式1:使用Make内置的wildcard函数获取子目录
Make的wildcard函数可以直接匹配目录,避免调用shell命令:
# 定义父文件夹路径 image_folder := ./your-parent-folder build.all.images: for f in $(wildcard $(image_folder)/*/); do \ # 去掉路径末尾的斜杠,得到子文件夹名称 img_name=$$(basename $$f); \ # 构建镜像,标签为子文件夹名称 docker build -t $$img_name $(image_folder)/$$img_name; \ done
方式2:转义shell命令中的$符号
把shell命令里的$(...)改为$$(...),让Make把$$解析为单个$传递给shell执行:
image_folder := ./your-parent-folder build.all.images: for f in $$(find $(image_folder) -type d -maxdepth 1 -mindepth 1 -exec basename {} \;); do \ echo $$f; \ docker build -t $$f $(image_folder)/$$f; \ done
注意:Makefile中多行shell命令需要用\换行,并且每行开头的缩进必须是Tab键(不能用空格)。
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

