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

在GNU Make 3.81中,如何避免Makefile define里Bash for循环变量展开

解决GNU Make中shell变量转义与脚本生成的问题

看起来你在Makefile里生成shell脚本时遇到了变量展开的坑,我来帮你拆解问题并修正:

核心问题分析

你生成的trial.sh里echo内容为空,主要是两个错误导致的:

  1. 错误的shell变量写法:echo $$(file) 其实是让shell执行file命令(查看文件类型的工具),而不是输出shell变量$file。在Makefile里传递shell变量的转义逻辑需要根据场景调整。
  2. 语法错误的重定向:你代码末尾的" > trial.sh; 引号位置完全错误,导致生成的脚本内容混乱。

修正后的代码示例

先给你一个能正常工作的版本,再逐个解释细节:

# 定义可复用的规则模板,注意转义细节
define create_area
$(1): $(2)
	mkdir -p $$(@D); \
	cp -nLr -v $(2)/* $$(@D); \
	cd $$(@D); \
	# 用单引号包裹生成的脚本内容,避免Make展开内部的$变量
	echo 'for file in *.v; do echo $file; done' > trial.sh;
endef

# 遍历A1/A2和B1的组合,生成对应规则
$(foreach a,$(A1) $(A2),\
	$(foreach b,$(B1),\
		$(eval $(call create_area,$(a),$(b)))))

关键修正点说明

  1. shell变量的正确传递:

    • 如果你是直接在Make的shell命令里使用$file,需要写成$$file(Make会把$$解析成单个$传递给shell)。
    • 但这里你是生成另一个shell脚本文件,需要让写入trial.sh的内容里保留$file,这时用单引号包裹echo的内容最省心——单引号在Make中不会展开内部的$,shell拿到的就是原始的$file。
    • 如果你偏好双引号,需要多转一层:echo "for file in *.v; do echo \$$file; done" > trial.sh;,Make会把\$$处理成$,最终写入trial.sh的是$file。
  2. 避免call/eval的替代方案:
    如果你想完全不用call,可以直接在foreach里拼接规则,虽然可读性差一点,但也能实现:

    $(foreach a,$(A1) $(A2),\
        $(foreach b,$(B1),\
     	   $(eval $(a): $(b))\
     	   $(eval $(a): ; mkdir -p $$(@D); cp -nLr -v $(b)/* $$(@D); cd $$(@D); echo 'for file in *.v; do echo $file; done' > trial.sh;)\
        )
    )
    

验证效果

修正后,生成的trial.sh内容会是:

for file in *.v; do echo $file; done

运行这个脚本时,就能正常遍历当前目录下的.v文件并输出文件名了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:34:50