Если я правильно понял, вы хотите удалить все файлы с именем:
src/**/migrations/0*.py
, где **
может быть чем угодно, включая вообще ничего.find
может сделать это в одиночку:
find src -path '*/migrations/0*.py' -delete
И, поскольку make recipes - это просто пустая оболочка, вам не нужно $(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
для удаления файлов без подтверждения.
EDIT 1 : если это упражнение о циклах и make, просто помните, что рецепты make - это скрипты оболочки (по одному на строку), которые сначала раскрываются make, а затем передаются в оболочку.Итак:
- Если вы хотите использовать переменные оболочки, используйте их в одну строку (но вы можете разбивать строки с помощью завершающего
\
).В противном случае они будут происходить из разных вызовов оболочки, и это не будет работать должным образом. - Если вы используете знак
$
в своем рецепте расширения оболочки, удвойте их, чтобы избежать первого расширения путем make.
В дальнейшем я предполагаю, что у вас нет имен каталогов или файлов с пробелами или специальными символами.Если вы это сделаете, пришло время задать вопрос о вашей оболочке.
Итак, с помощью оболочки bash, например, мы можем сначала создать массив целевых каталогов, а затем зациклить их, чтобы удалить файлы:
SHELL := bash
remove:
dirs=( $$(find src -type d -name migrations) ); \
for d in "$${dirs[@]}"; do \
rm -f "$$d"/0*.py; \
done
EDIT 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
- путь к каталогу.И эти правила статические правила .В рецепте автоматическая переменная $*
расширяется на make как основа шаблона clean-%
.Таким образом, если DIR
равно src/foo/bar/migrations
, правило для него эквивалентно:
clean-src/foo/bar/migrations:
rm -f src/foo/bar/migrations/0*.py
Основное преимущество этого стиля перед циклом оболочки состоит в том, что make может запускать все рецепты параллельно.Если у вас есть сотни migrations
каталогов, и если у вас 8 или 16 ядер на вашем компьютере, это действительно может иметь значение.Просто попробуйте:
make -j1 remove
make -j16 remove
, и вы увидите разницу.