Как проверить строку, содержит ли она подстроку в командах Makefile

#bash #makefile #gnu-make

#bash #makefile #gnu-make

Вопрос:

Я хочу проверить, содержит ли строковая переменная указанную подстроку в Makefile. Цель состоит в том, чтобы очистить вложенные папки. Я использовал приведенный ниже код, но он не сработал.

 SERVICES_LIST = A_Service B_Service C_Service #example
SPECIFIC_SERVICE_LIST = A_Service B_Service
clean:
    @list='$(SERVICES_LIST)';for subdir in $$list;do 
                echo "clean in $$subdir";
                if [[ "*$$subdir*" == "$(SPECIFIC_SERVICE_LIST)" ]];then
                make $$subdir clean;
                fi;
   done;
  

Комментарии:

1. Пожалуйста, отформатируйте свой вопрос, используя функции форматирования SO, чтобы его было легче читать. Кроме того, задавая вопросы, пожалуйста, не говорите что-то вроде «это не сработало»; это никому не поможет понять ситуацию. Вместо этого покажите введенную вами команду и полученный результат (или, если вывода много, по крайней мере, все сообщения об ошибках, а не только последние строки!! На самом деле ПЕРВЫЕ сообщения об ошибках почти всегда важнее последних, хотя лучше включать все ошибки, если их не слишком много).

2. Измените порядок проверки на равенство и поместите звездочки вне кавычек: if [[ "$(SPECIFIC_SERVICE_LIST)" == *"$$subdir"* ]]

3. В любом случае, @Beta == выполняет сравнение строк, а не сравнение соответствия шаблону.

4. @JohnBollinger: И в этом случае это работает.

Ответ №1:

Это не имеет большого отношения к make , потому что практически вся задействованная логика выражена на языке оболочки. В частности, вы, похоже, предполагаете bash .

Проблема здесь:

                 if [[ "*$$subdir*" == "$(SPECIFIC_SERVICE_LIST)" ]];then
  

Похоже, вы пытаетесь сопоставить ( make расширение) "$(SPECIFIC_SERVICE_LIST)" с шаблоном глобуса, сформированным как ( make расширение) "*$$subdir*" . Но левая часть заключена в кавычки, поэтому она не интерпретируется как шаблон, и == оператор выполняет (точное) сопоставление строк, а не сопоставление с образцом.

Один из основных способов применения таких тестов сопоставления с образцом на языке оболочки case — это использовать конструкцию, поскольку выражения выбора, используемые с ней, всегда интерпретируются как глобусы. Это может выглядеть так в вашем makefile:

 case "$(SPECIFIC_SERVICE_LIST)" in *$$subdir*) make $$subdir clean ;; esac
  

Но все это кажется довольно неидиоматичным. Вообще говоря, makefile настроен на проект. Даже если она генерируется динамически частично или полностью, разумно и целесообразно спроектировать вашу систему сборки так, чтобы чистая цель могла делать что-то более похожее на это:

 clean:
    for subdir in $(SPECIFIC_SERVICE_LIST); do make -C $$subdir clean; done
  

… или, может быть, так:

 clean: clean_services
    ...

clean_services:
    for subdir in $(SPECIFIC_SERVICE_LIST); do make -C $$subdir clean; done
  

Комментарии:

1. Я меняю на if [[ «$(SPECIFIC_SERVICE_LIST)» == *»$$subdir»* ]], но, похоже, как вы сказали, это не совпадение с шаблоном, просто сравнение строк. Просто для подтверждения, нет ли способа использовать if для сопоставления строки шаблона в части команды Make? Спасибо!

Ответ №2:

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

 $ cat Makefile
SERVICES_LIST = A_Service B_Service C_Service #example
SPECIFIC_SERVICE_LIST = A_Service B_Service

.PHONY: $(addsuffix -clean, $(SERVICES_LIST))
$(addsuffix -clean, $(SERVICES_LIST)): %-clean:
        $(MAKE) -C $* clean

.PHONY: clean
clean: $(addsuffix -clean, $(SPECIFIC_SERVICE_LIST))