到目前为止,我正在尝试执行以下操作但未成功:
remove:
for file in $(shell find src/ -name migrations -type d); do rm $(wildcard "$(file)/0*.py"); done
答案 0 :(得分:1)
如果我理解得很好,您想删除所有名为:
的文件。src/**/migrations/0*.py
其中**
可以是任何东西,包括任何东西。 find
可以单独执行此操作:
find src -path '*/migrations/0*.py' -delete
由于制作食谱只是裸露的外壳,因此不需要$(shell...
或类似的东西:
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
删除未经确认的文件。编辑1 :如果这是关于循环和make的练习,只需记住make配方是shell脚本(每行一个),首先由make扩展,然后再传递给shell。所以:
\
来换行)。否则,它们将来自不同的Shell调用,并且无法按预期工作。$
符号进行外壳扩展,请将其加倍以按make进行第一个扩展。在下文中,我假定您没有带有空格或特殊字符的目录或文件名。如果这样做,是时候问一个关于您的shell的问题了。
例如,使用bash shell,我们可以首先构建目标目录的数组,然后循环遍历它们以删除文件:
SHELL := bash
remove:
dirs=( $$(find src -type d -name migrations) ); \
for d in "$${dirs[@]}"; do \
rm -f "$$d"/0*.py; \
done
编辑2 :您还可以将内置make循环系统与每个目录一个(语音) clean 目标一起使用。
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
是目录路径。这些规则是static pattern rules。在配方中,$*
make自动变量由make扩展为clean-%
模式的茎。因此,如果DIR
为src/foo/bar/migrations
,则其规则等效于:
clean-src/foo/bar/migrations:
rm -f src/foo/bar/migrations/0*.py
这种样式在shell循环上的主要优点是make可以并行运行所有配方。如果您有数百个migrations
目录,并且计算机上具有8或16个内核,则确实可以有所作为。只需尝试:
make -j1 remove
make -j16 remove
您将看到区别。
答案 1 :(得分:0)
简短的答案是你不能这样做。
编写makefile配方以清楚了解它们的工作原理很关键:首先,make将扩展所有make变量和函数。然后,make会将结果字符串传递给要运行的shell。最后,make等待外壳程序完成,然后检查退出代码以查明它是否成功。
在这里,您尝试使用外壳程序for
循环,其中循环主体调用make wildcard
函数。这行不通。
考虑一下您要make(和shell)执行的操作:shell会运行其for循环,然后每次执行循环主体时,它都会进行通信以返回一些shell变量的值,并且make使用该变量扩展make通配符函数,然后将结果返回给Shell以进行更多处理。根本不可能。
最好是使用 shell 结构编写配方。一条好的经验法则是,在配方内部使用make的shell
函数绝不是一个好主意:配方已经在外壳中运行,因此根本不需要shell
函数。简直令人困惑。同样,您几乎不需要在食谱中使用make的wildcard
函数,因为shell会自动为您提供文件glob。
我会这样写:
remove:
find src/ -name migrations -type d | while read -r dir; do rm "$$file"/0*.py; done
请注意,我们用两个美元符号对$$file
进行了转义,以防止make扩展为make变量。