You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GNU Make中正确包含/执行命令输出以定义变量?

GNU Make 正确解析Shell命令输出的变量定义

问题场景

有一个生成Make变量定义的Shell脚本test.sh:

echo 'V1 = foo bar'
echo 'V2 = ab cd'

直接在Makefile中使用$(eval $(shell ./test.sh))时,由于$(shell)函数会将命令输出的换行符替换为空格,导致变量解析错误:

Makefile代码:

$(eval $(shell ./test.sh))
$(info V1='$(V1)')
$(info V2='$(V2)')

错误输出:

V1='foo bar V2 = ab cd'
V2=''

期望输出:

V1='foo bar'
V2='ab cd'

解决方案

方法1:通过foreach逐行解析输出

利用Make的foreach循环,先将Shell输出按换行拆分,再逐个执行eval处理每行的变量定义:

# 定义换行符(注意中间要留空行)
define NL


endef

# 捕获Shell输出,替换换行为列表分隔符后逐行eval
$(foreach line,$(subst $(NL), ,$(shell ./test.sh)),$(eval $(line)))

$(info V1='$(V1)')
$(info V2='$(V2)')

核心是通过subst将换行符转换为Make列表的空格分隔符,再用foreach遍历每一行内容执行eval,确保每个变量定义被单独解析。

方法2:修改输出格式直接生成eval语句

调整Shell脚本,让输出内容直接包含eval指令,这样Make会自动执行每个变量定义:
修改后的test.sh:

echo '$(eval V1 = foo bar)'
echo '$(eval V2 = ab cd)'

对应的Makefile:

$(shell ./test.sh)
$(info V1='$(V1)')
$(info V2='$(V2)')

如果不想修改原脚本,也可以在Make中通过sed处理输出:

$(shell ./test.sh | sed 's/^/$$(eval /; s/$$/)/')
$(info V1='$(V1)')
$(info V2='$(V2)')

sed会给每行添加$(eval 前缀和)后缀,让Shell输出直接成为可执行的Make指令。

方法3:临时文件+include(最兼容方案)

如果上述方法存在版本兼容问题,最稳妥的方式是将Shell输出写入临时文件,再用include指令加载:

# 生成临时文件路径
temp_vars := $(shell mktemp)
# 将脚本输出写入临时文件
$(shell ./test.sh > $(temp_vars))

# 加载临时文件中的变量定义
include $(temp_vars)

# 清理临时文件的目标
.PHONY: clean
clean:
	rm -f $(temp_vars)

$(info V1='$(V1)')
$(info V2='$(V2)')

这种方法不受$(shell)换行替换的影响,兼容性最好,适合复杂的变量定义场景。

内容的提问来源于stack exchange,提问作者Thierry Lelegard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 06:55:17