Есть ли способ иметь несколько подстановочных знаков? - PullRequest
0 голосов
/ 04 апреля 2019

Я пытаюсь использовать GNU make для организации моих исследований, обработки и визуализации в соответствии с рекомендациями Data Science CookieCutter . Мои необработанные данные структурированы так:

.
├── data
│   ├── interim
│   │   └── cleaned
│   └── raw
│       ├── ex01
│       └── ex02

Где я храню данные эксперимента 1 и 2 отдельно, но объединяю их после очистки. Например, data/raw/ex01/p0-c0.csv становится data/interim/cleaned/ex01-p0-c0.hdf.

В make Я использую два таких правила:

data/interim/cleaned/ex01-%.hdf: data/raw/ex01/source0/%.csv 
data/raw/ex01/source1/%.csv
  $(PYTHON) src/data/make_dataset.py $^ $@

data_interim_cleaned_ex01: $(addprefix $(CLEANED_DIR)/ex01-, $(addsuffix .hdf, $(basename $(basename $(notdir $(wildcard data/raw/ex01/source0/*.csv))))))

Это кажется мне странно многословным (особенно потому, что я скопировал блок для эксперимента 2), и моя интуиция подсказывает мне, что было бы проще, если бы было несколько (именованных) групповых символов. Я думаю, что регулярные выражения помогли бы, но не (легко) доступны в make .

Есть ли канонический способ решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 06 апреля 2019

Ответ, возможно, не тот, который вам понравится, но он не должен вводить изменчивость или повторение в ваших именах файлов. Есть простые или, по крайней мере, разумные способы сформулировать отношения в Makefile между именами основ, где вы добавляете или удаляете префикс (такой как имя каталога) или суффикс. Все остальное создает осложнения, когда вы сталкиваетесь с замученными и сложными правилами преобразования или внешними вспомогательными сценариями для управления сопоставлениями, или, в худшем случае, с ситуацией, когда вам просто нужно отказаться от make для управления зависимостями.

Один из обходных путей, который позволяет вам сохранить свой торт и съесть его, - это установить символические ссылки между вашими предпочтительными, дружественными для человека соглашениями об именах и структурами, управляемыми make; но в лучшем случае это костыль.

Другая техника, которая может быть вам полезна, - touch простой файл флага, чтобы пометить сложный набор зависимостей как обработанный. Особенно, если есть зависимости, которые не отображаются напрямую в набор имен входных файлов для другой цели, оставляя все эти значения за простым

.input-files-done: some complex depencies
    touch $@

, а затем просто зависимость от .input-files-done для целей, которые разделяют эти зависимости, может упростить ваш Makefile и рабочий процесс.

Но, в заключение, моя основная рекомендация - сохранять имена файлов единообразными, чтобы вы всегда могли объявить явную зависимость от одного имени файла к другому с помощью простого правила.

0 голосов
/ 06 апреля 2019

Следующее решение на самом деле не является каноническим make файлом, но ИМХО, большая часть канонической функциональности make слишком трудна для понимания и запоминания в любом случае.Такие вопросы, как «как я могу преобразовать мой набор имен файлов из формы X в Y», возникают постоянно, потому что пользователи do используют структуру каталогов и файлов в качестве средства организации своих проектов (очень естественный и логичный способ)make действительно плохо приспособлен для программной обработки таких задач.

Один из способов - использовать обычный набор инструментов командной строки, таких как sed, другой - вспомогательные библиотеки, такие как gmtt разбирать строки:

include gmtt-master/gmtt.mk

COMMON_ROOT = data/raw
COMMON_DEST = data/interim/cleaned

SOURCE = data/raw/ex01/p0-c0.csv data/raw/ex01/p1-c1.csv data/raw/ex02/p0-c0.csv data/raw/ex02/p1-c1.csv

# a pattern which separates a string into 5 parts (see below)
SEP_PATTERN = $(COMMON_ROOT)/ex*/*.csv

# use the elements (quoted variable-references '$$'!) in the new filename 
OUTPUT_PATTERN = $(COMMON_DEST)/ex$$2-$$4.hdf

# glob-match tests a glob pattern on a string and returns the string cut up at the border of 
# the glob elements (*,?,[] and verbatim strings). We immediately turn this into a gmtt table 
# by prepending the number of columns (5) to it:
SEPARATED = 5 $(foreach fname,$(SOURCE),$(call glob-match,$(fname),$(SEP_PATTERN)))

$(info $(SEPARATED))
$(info -----------------) 
$(info $(call map-tbl,$(SEPARATED),$(OUTPUT_PATTERN)$$(newline)))

Вывод:

$ make
5 data/raw/ex 01 / p0-c0 .csv data/raw/ex 01 / p1-c1 .csv data/raw/ex 02 / p0-c0 .csv data/raw/ex 02 / p1-c1 .csv
-----------------
data/interim/cleaned/ex01-p0-c0.hdf
data/interim/cleaned/ex01-p1-c1.hdf
data/interim/cleaned/ex02-p0-c0.hdf
data/interim/cleaned/ex02-p1-c1.hdf

make: *** Keine Ziele.  Schluss.

Боюсь, что превращение make-файла в файл, который генерирует правила динамически, неизбежно, хотя.

...