如何让Makefile Recipe中的Bash循环在命令失败时立即终止
解决Makefile中jsonnet命令失败时立即终止流程的问题
修改后的Makefile代码(GNU环境)
run_pipelines: @[ "${filter}" ] || filter="."; \ filter=$$(echo "$$filter" | sed -e 's/\./.*/g') && echo $${filter}"<3" && \ echo "\033[1;34m#######Running Pipelines for $${filter}#######\033[0m" && \ find v2/services -type f -regex ".*$${filter}.*.jsonnet" -print0 | \ xargs -r -0 --exit-on-error -I {} bash -e -c 'echo -e "\033[1;32mjsonnet {} \033[0m"; jsonnet {}' .PHONY: run_pipelines
关键修改点说明
修复filter变量赋值的隐藏bug
原来的( filter="."; )是在子shell中执行,赋值的变量无法传递到后续命令,导致未指定filter时,后续sed处理会得到空值,find的正则匹配完全失效。改成filter=".";让变量在当前shell生效,确保逻辑正确。让bash脚本遇错即停
使用bash -e选项,只要脚本内的任何命令返回非零状态,bash就会立即退出,替代原来手动写的|| exit $?,逻辑更简洁可靠。强制xargs第一个失败就停止
添加--exit-on-error选项(GNU xargs支持),告诉xargs只要某个被执行的命令失败,就立刻停止处理剩余的文件,避免继续执行后续jsonnet命令。
通用兼容版(适配BSD等非GNU环境)
如果你的环境不支持--exit-on-error,可以改用for循环替代xargs,利用make本身的特性——只要recipe中某条命令失败就终止:
run_pipelines: @[ "${filter}" ] || filter="."; \ filter=$$(echo "$$filter" | sed -e 's/\./.*/g') && echo $${filter}"<3" && \ echo "\033[1;34m#######Running Pipelines for $${filter}#######\033[0m" && \ for file in $$(find v2/services -type f -regex ".*$${filter}.*.jsonnet"); do \ echo -e "\033[1;32mjsonnet $$file \033[0m"; \ jsonnet $$file; \ done .PHONY: run_pipelines
这个版本中,只要某个jsonnet命令失败,for循环就会终止,整个recipe返回失败状态,make也会停止运行。
内容的提问来源于stack exchange,提问作者anwerj
相关产品推荐
相关产品推荐

