Makefile 在字符串中进行变量替换

Makefile 在字符串中进行变量替换,makefile,gnu-make,Makefile,Gnu Make,假设我定义了一个json文件: foo.json: 生成文件: 问题是:如何通过make的变量替换或echo的BASH替换来扩展变量${VALUE},从而在输出上保留有效JSON文件中的双引号(yes make保留它们,yes,echo$(foo)也会计算变量——但会删除双引号——是的,我不关心是否会删除换行符) 至于这一切的原因,假设我有一个例程,它需要一个相当于一种语言(而不是一个配置)的表达性JSON文件,我使用Make来控制系统: .PHONY: generator # in the

假设我定义了一个json文件:

foo.json

生成文件:

问题是:如何通过make的变量替换或
echo
的BASH替换来扩展变量
${VALUE}
,从而在输出上保留有效JSON文件中的双引号(yes make保留它们,yes,
echo$(foo)
也会计算变量——但会删除双引号——是的,我不关心是否会删除换行符)

至于这一切的原因,假设我有一个例程,它需要一个相当于一种语言(而不是一个配置)的表达性JSON文件,我使用Make来控制系统:

.PHONY: generator

# in the language of control theory
generator: $(foreach q,${Qm},.Qmarked-startup-$q)
    application $@ -i <(pseudo code: {envsubst $@.json})

.Qmarked-startup-%: $(pseudo code: q0 dependencies ... )
    # $* here is a verb
    application $* -i <(pseudo code: {envsubst $*.json})
.PHONY:generator
#用控制论的语言
生成器:$(foreach q,${Qm},.Qmarked启动-$q)

应用程序$@-i如果运行此生成文件:

export VALUE=bar
SHELL=/usr/bin/env bash
foo=$(shell cat foo.json)

bar:
    $(warning $(foo))
您可以看到$(foo)确实包含双引号。但美元价值并未扩大

您可以尝试以下方法:

export VALUE=bar
SHELL=/usr/bin/env bash
foo=$(shell VALUE=$(VALUE) envsubst < foo.json)

bar:
    @echo '${foo}'
export VALUE=bar
SHELL=/usr/bin/env bash
foo=$(shell值=$(值)envsubst
如果要从Make的环境中展开变量,可以使用
eval
展开赋值中的变量

假设您不介意按照@MadScientists的注释将所有行标记在一起,您可以将注释变灰并将json组合成一行,如下所示:

export VALUE:=bar

foo:=$(shell grep -v "^\S*//" foo.json)
$(info foo=[$(foo)])

$(eval foo2:=$(shell grep -v "^\S*//" foo.json))
$(info foo2=[$(foo2)])

bar:
        @echo "from recipe: foo2=[$(subst ",\",$(foo2))]"
$(subst“,\”,…)
在发送到bash之前转义引号。这将产生:

foo=[{"key":"${VALUE}"}]
foo2=[{"key":"bar"}]
from recipe: foo2=[{"key":"bar"}]

注意:安全考虑——如果外人可以访问foo.json,那么他们可以使用maker的权限运行他们想要的任何东西。

您到底希望该makefile打印什么?如果您向我们展示您真正想要做的事情会更好。这不太可能(使用
$(shell…
)实现您真正想做的事情,因为它总是丢弃所有换行符(例如)。如果我们知道您真正想要实现的是什么,而不是
echo…
,那么可能有更好的方法来实现它。@MadScientist编辑并更新了。如果您的示例中没有注释
//foo.json
,那么您就不在乎换行符了。。。如果您有,那么当删除换行符时,您的整个JSON文件都将被注释掉…@madsciient该注释是指标记的上下文在foo.JSON文件中。我认为您不需要配方中的
$(subst…
)。只需将echo放在单引号中,这样shell就不会弄乱内容:
@echo'from recipe:foo2=[$(foo2)]”
而且我认为您可以忽略注释:OP可能在其环境中实际上没有任何注释。我认为它非常简单:
$(eval foo=$(shell cat foo.json))
(如果您愿意,也可以使用
:=
来简单扩展
foo
export VALUE:=bar

foo:=$(shell grep -v "^\S*//" foo.json)
$(info foo=[$(foo)])

$(eval foo2:=$(shell grep -v "^\S*//" foo.json))
$(info foo2=[$(foo2)])

bar:
        @echo "from recipe: foo2=[$(subst ",\",$(foo2))]"
foo=[{"key":"${VALUE}"}]
foo2=[{"key":"bar"}]
from recipe: foo2=[{"key":"bar"}]