for makefile中的shell循环

问题描述 投票:3回答:2

我写了一个makefile,希望它可以像这样顺序生成文件

1.out
2.out
3.out

makefile

TOUCH := $(shell for n in 'seq 1 3'; do echo $$n ;done)
.PHONY: test
test:
    @$(TOUCH)

[确定]取得结果:

1
2
3

但是,当我用touch替换echo时,

TOUCH := $(shell for n in 'seq 1 3'; do touch $$n.out ;done)

[错误]产生结果:

1
seq
3.out
makefile
2个回答
8
投票

您似乎在这里混合了两个完全独立的结构。

VARIABLE := value

value分配给变量。

VARIABLE := $(shell echo value)

将使用外壳程序生成一个字符串,然后将该字符串分配给VARIABLE。这是在解析Makefile时发生的,即在Make尝试实际执行任何配方之前。

我想您正在寻找它:

TOUCH := for n in $$(seq 1 3); do touch $$n.out; done
.PHONY: test
test:
        @$(TOUCH)

当然也可以内联;

.PHONY: test
test:
        @for n in $$(seq 1 3); do touch $$n.out; done

但是,更好的设计是让Make负责:

.PHONY: test
test: 1.out 2.out 3.out
%.out:
        @touch $@

((我个人会在所有地方都省略@前缀,这样您就可以看到发生了什么。调试完东西后,如果输出困扰您,请使用make -s运行。)


2
投票

这里有很多问题。

您在外壳程序代码中使用单引号而不是反引号。单引号创建字符串。反引号执行命令。

因此,当您编写for n in 'seq 1 3'; do echo $$n; done时,shell所做的工作是遍历单个字符串“ seq 1 3”的列表,而不遍历数字1、2和3。

这导致TOUCH的值为“ seq 1 3”。

[然后在规则TOUCH行上展开@$(TOUCH)时,该行将变为@seq 1 3,然后Shell为您执行并输出

1
2
3

但不是出于您的想法。 (删除前导@,您会看到它。)

如果我们查看不起作用的示例,请提供该信息

TOUCH := $(shell for n in 'seq 1 3'; do touch $$n.out ;done)

将循环体touch $$n.out替换为字符串“ seq 1 3”以获取$$n

这将为我们提供一个touch seq 1 3.out调用,该调用运行$(shell)并创建您在帖子中列出的文件和一个空的touch seq 1 3.out变量。这就解释了为什么(尽管您没有要求)却得到TOUCH test'make: Nothing to be done for \ make`。

我还应该明确指出,您的as output from running / echo运行是在touch调用期间完成的,而not$(shell)规则执行期间完成了。那可能不是您想要的。不要使用简单扩展的test变量,也不要将命令放在变量中运行,也不要使用:=

© www.soinside.com 2019 - 2024. All rights reserved.