Вопрос или проблема
После сборки с помощью make
я хочу переместить все файлы, которые оканчиваются на .cache.{js,woff}
, в подпапку.
(cd $(PFROOT)/PVWR2/gwt/pdfwebviewer/; \
mkdir -p cache_files; \
mv *.cache.{js,woff} sub_folder)
Проблема в том, что при запуске make
он, похоже, интерпретирует *.cache.{js,woff}
как имя файла, а не что-то динамическое, и, конечно, нет файла с явным именем *.cache.{js,woff}
.
Когда я просто перехожу в папку и перемещаю вручную через терминал с командой выше,
это работает без проблем.
Я понимаю, что это связано с глоббингом, но не знаю, как это исправить.
{...}
— это синтаксис bash для расширения фигурных скобок, но make по умолчанию использует /bin/sh
вместо bash
.
Из info make
, раздел 5.3.2:
Программа, используемая в качестве оболочки, берется из переменной
SHELL
. Если эта переменная не установлена в вашем makefile, программа/bin/sh
используется как оболочка.
Если вы хотите использовать bash для разбора конструкций оболочки в вашем Makefile, вы можете добавить следующее в начало:
SHELL := /bin/bash
Ответ или решение
Когда вы работаете с Makefile и командой mv *.cache.{js,woff} sub_folder
, возникает проблема в интерпретации этой команды на уровне командной оболочки. Вы столкнулись с особенностями работы Makefile, где появление ошибок может быть связано с неправильной интерпретацией конструкции оболочки (Command-shell construction).
Теория (Theory)
Для начала важно понимать, как функционирует оболочка в контексте Makefile. GNU Make по умолчанию использует /bin/sh
как оболочку для команд. Эта оболочка в большинстве систем Unix-подобных не является bash и не поддерживает некоторые специфичные для bash конструкции, такие как brace expansion, используемую в команде *.cache.{js,woff}
.
1. Глоббинга и brace expansion:
Глоббинг — это термин, обозначающий расширение шаблонов файлов в набор имен файлов. Конструкция *.cache.{js,woff}
должна расшириться в два шаблона *.cache.js
и *.cache.woff
. Однако brace expansion является функцией bash, и если ваша команда интерпретируется в оболочке sh
, это приведет к интерпретации всего выражения как одной строки, а не расширения в отдельные файлы.
Пример (Example)
При выполнении команды в shell взаимодействие происходит следующим образом:
# Открытие bash оболочки
$ cd /путь/к/вашей/директории
$ mv *.cache.{js,woff} sub_folder
Здесь команда выполняется bash, где расширение скобок происходит корректно: *.cache.js
и *.cache.woff
подставляются вместо конструкции {js,woff}
. Команда mv
затем перемещает все файлы, которые соответствуют этим паттернам, в каталог sub_folder
.
Применение (Application)
Если вам необходимо обязать Make использовать bash, вы можете изменить оболочку, добавив соответствующую строчку в Makefile:
SHELL := /bin/bash
Это позволит использованию bash-расширений типа brace expansion. Вот как ваш Makefile должен выглядеть после изменения:
SHELL := /bin/bash
target_name:
(cd $(PFROOT)/PVWR2/gwt/pdfwebviewer/; \
mkdir -p cache_files; \
mv *.cache.{js,woff} cache_files)
Однако, если смена оболочки нет возможности по ряду причин (например, система не поддерживает bash), вы можете изменить команду следующим образом, минуя brace expansion и нарушая совместимость со старыми POSIX-compliant конструкциями:
target_name:
(cd $(PFROOT)/PVWR2/gwt/pdfwebviewer/; \
mkdir -p cache_files; \
mv *.cache.js *.cache.woff cache_files)
В случае сложных шаблонов, которые не могут быть обработаны однозначно простой заменой, можно использовать find
и sed
или другие утилиты командной строки для достижения цели в более POSIX-совместимой форме:
target_name:
(cd $(PFROOT)/PVWR2/gwt/pdfwebviewer/; \
mkdir -p cache_files; \
find . -maxdepth 1 -name '*.cache.js' -exec mv {} cache_files \; \
-name '*.cache.woff' -exec mv {} cache_files \;)
Здесь используется утилита find
, которая проходит по файловой системе, находит файлы, соответствующие шаблону, и выполняет команду mv
для каждого найденного файла.
Заключение
Проблема с вашей Makefile заключается в использовании конструкции, специфичной для bash, в оболочке sh. Понимание, какие функции поддерживаются текущей оболочкой, поможет избежать подобных ошибок. Смена оболочки, корректировка шаблонов или использование файловых утилит для обхода ограничений POSIX – это пути для успешного решения вашей проблемы.