如何在Makefile中使用for、find和通配符?
到目前为止,我正在尝试做以下工作,但没有取得任何成功:如何在Makefile中使用for、find和通配符?,makefile,Makefile,到目前为止,我正在尝试做以下工作,但没有取得任何成功: remove: for file in $(shell find src/ -name migrations -type d); do rm $(wildcard "$(file)/0*.py"); done 如果我理解清楚,您希望删除所有名为: src/**/migrations/0*.py 其中,**可以是任何内容,包括任何内容查找可以单独执行此操作: find src -path '*/migrations/0*.py'
remove:
for file in $(shell find src/ -name migrations -type d); do rm $(wildcard "$(file)/0*.py"); done
如果我理解清楚,您希望删除所有名为:
src/**/migrations/0*.py
其中,**
可以是任何内容,包括任何内容<代码>查找可以单独执行此操作:
find src -path '*/migrations/0*.py' -delete
由于make配方只是简单的外壳,您不需要$(外壳…
或类似的东西:
remove:
find src -path '*/migrations/0*.py' -delete
但在运行此潜在危险规则之前,您可能应该使用此规则,直到您满意为止:
remove:
find src -path '*/migrations/0*.py' -ok rm {} \;
唯一的区别是,它会在删除文件之前要求您确认。我们还可以让所有这些变得更简单:
remove-safe: DELCMD := -ok rm {} \\;
remove-unsafe: DELCMD := -delete
remove-dry-run: DELCMD := -print
remove-safe remove-unsafe remove-dry-run:
find src -path '*/migrations/0*.py' $(DELCMD)
根据您的需要使用一个或另一个目标:
打印将被删除的文件列表,而不删除它们remove dry run
要删除文件并确认remove safe
可在未经确认的情况下删除文件remove unsafe
\
)分隔行。否则,它们将来自不同的shell调用,无法按预期工作$
登录您的shell扩展配方,请将它们加倍以通过make退出第一次扩展SHELL := bash
remove:
dirs=( $$(find src -type d -name migrations) ); \
for d in "$${dirs[@]}"; do \
rm -f "$$d"/0*.py; \
done
编辑2:您还可以使用内置的生成循环系统,每个目录有一个(假的)干净目标
DIRS := $(shell find src -type d -name migrations)
clean-targets := $(addprefix clean-,$(DIRS))
.PHONY: remove $(clean-targets)
remove: $(clean-targets)
$(clean-targets): clean-%:
rm -f "$*"/0*.py
棘手的部分是:
$(clean-targets): clean-%:
rm -f "$*"/0*.py
规则。它相当于每个migrations
目录有一条规则,即:
clean-DIR: clean-%:
rm -f "$*"/0*.py
其中,DIR
是目录路径。这些规则是。在配方中,$*
make自动变量由make展开,作为clean-%
模式的主干。因此,如果DIR
是src/foo/bar/migrations
,则其规则等效于:
clean-src/foo/bar/migrations:
rm -f src/foo/bar/migrations/0*.py
与shell循环相比,此样式的主要优点是make可以并行运行所有配方。如果您有数百个迁移
目录,并且您的计算机上有8个或16个内核,那么它确实可以带来不同。请尝试:
make -j1 remove
make -j16 remove
你会看到区别。简单的回答是你不能那样做 编写makefile配方时,您必须清楚了解它们的工作原理:首先,make将扩展所有make变量和函数。然后,make将结果字符串传递给要运行的shell。最后,make将等待shell完成并检查退出代码,以确定是否成功 这里您试图使用shell
for
循环,其中循环体调用make通配符
函数。这无法工作
考虑你想要做什么(和外壳)要做的事情:shell将运行其for循环,然后每次执行循环体时,它都会返回通信以生成某个shell变量的值,make将使用该变量展开make通配符函数,然后将结果返回给shell进行更多处理。这是不可能的
最好是使用shell构造编写配方。一个好的经验法则是,在配方中使用make的shell
函数从来都不是一个好主意:配方已经在shell中运行,因此您根本不需要shell
函数。这很容易混淆。同样,您很少需要make的通配符函数,因为shell会自动为您创建文件
我将这样写:
remove:
find src/ -name migrations -type d | while read -r dir; do rm "$$file"/0*.py; done
注意,我们用两个美元符号转义了$$file
,以防止make将其扩展为make变量。我知道我可能可以用find…-exec rm-fr{}来实现这一点\;
但是问题更多的是关于在makefileOr中使用通配符和带有shell调用的循环,或者按照Renaud的建议,使用没有shell循环的just find。