Makefile中将jq命令输出赋值给变量后结果为空的解决方法
问题根因
你遇到的变量为空问题由两个核心错误导致:
- 变量引用语法混用:你在shell命令逻辑中定义的
UPDATE_ENVVARS是shell进程内的局部变量,但echo输出时使用了Makefile变量语法${UPDATE_ENVVARS}。Make在执行命令前会优先展开所有自身语法的变量引用,由于你从未在Makefile上下文定义过同名变量,该引用会被直接替换为空字符串,最终传给shell执行的就是echo "",自然没有输出。 - Make的shell执行机制问题:Make默认会为target下的每一行独立命令启动单独的shell进程,就算你修正了变量引用,如果后续使用变量的命令没有和赋值命令放在同一个shell会话中,上一个进程退出时定义的shell变量会直接销毁,后续命令无法读取到值。
修复方法
方案1:保留原有续行写法,修正变量引用
只需要把echo位置的Make风格变量引用改成shell变量引用即可,注意shell变量在Makefile中需要用双美元符号$$转义,告诉Make不要提前展开该变量,直接交给shell解析。修正后的target写法如下:
update-env: echo "{ \"Variables\":${ENV_VALUE}}" > ./new_env.json && \ UPDATE_ENVVARS=$$(jq -s '.[0] as $$a |.[1] as $$b | $$a * $$b' old_env.json new_env.json | jq -c . ) && \ echo "$$UPDATE_ENVVARS" # 后续要复用该变量的命令,必须通过&& \ 续行和上面的命令保持在同一个shell会话中,例如: # && curl -X POST -H "Content-Type: application/json" -d "$$UPDATE_ENVVARS" https://your-api.com
额外优化:你的jq合并逻辑可以简化,不需要两次调用jq、也不需要显式定义临时变量,直接写成jq -s '.[0] * .[1]' -c old_env.json new_env.json就能得到同样的压缩合并结果。
方案2:开启ONESHELL模式简化写法(推荐)
如果你使用的是GNU Make 3.82及以上版本,可以在Makefile开头开启.ONESHELL特性,同一个target下的所有命令会默认在同一个shell进程中执行,不需要写大量续行符,可读性更高:
# 放在Makefile顶部即可 .ONESHELL: SHELL := /bin/bash update-env: echo "{ \"Variables\":${ENV_VALUE}}" > ./new_env.json UPDATE_ENVVARS=$$(jq -s '.[0] * .[1]' -c old_env.json new_env.json) echo "$$UPDATE_ENVVARS" # 后续命令直接写在这里即可,直接用$$UPDATE_ENVVARS就能读取到合并后的JSON值 # other_command "$$UPDATE_ENVVARS"
修正后再执行你原来的make调用命令,就能正常输出合并后的JSON内容,后续命令也可以正常复用该变量。
内容的提问来源于stack exchange,提问作者azngunit81
相关产品推荐
相关产品推荐

