Как удалить все, кроме каталога в Makefile? - PullRequest
1 голос
/ 08 июня 2019

В командной строке Linux работает следующий набор команд.

%cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)

Но это не работает в Makefile

Команда Linux - работает

%cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)

Команда в Makefile

        @cd ${ADIR}/exe; shopt -s extglob; rm -rf !\(BDIR\)

Создать файл сообщения

rm: cannot remove `!(BDIR)': No such file or directory

Ответы [ 2 ]

1 голос
/ 08 июня 2019

К сожалению, есть странное поведение bash, в котором настройка shopt не вступит в силу до новой строки, поэтому любой всплывший на той же строке не распознает его. Попробуйте это в командной строке:

$ shopt -s extglob; echo !(BDIR)
bash: !: event not found

Тогда попробуйте в две строки:

$ shopt -s extglob
$ echo !(BDIR)
  ...works

К сожалению, это означает, что это почти невозможно использовать с make.

Вам следует использовать POSIX-совместимую версию, предложенную в комментарии triplee, и вообще избегать необходимости в специальных оболочках.

О, кажется, ответ был удален. В любом случае, сделайте что-то подобное вместо этого:

foo:
        cd ${ADIR}/exe && for f in *; do \
            case $$f in (BDIR) : ok ;; (*) rm -rf "$$f" ;; esac; \
        done
1 голос
/ 08 июня 2019

Проблема с вашим Makefile в том, что он экранирует ( и ), что заставляет оболочку интерпретировать их буквально.

Вторая проблема,

/bin/sh: -c: line 0: syntax error near unexpected token `('

, вызванаmake с использованием sh для выполнения команд, а не bash.

Синтаксис с подстановочными знаками !(...)extglob) поддерживается только bash, но не sh.

Youможет вызвать bash явно:

        @bash -c 'cd ${ADIR}/exe; shopt -s extglob; rm -rf !(BDIR)'

Но это тоже не сработает, потому что extglob не вступит в силу, пока не будет прочитана следующая строка ввода, поэтому !( ) по-прежнему выбрасываетсинтаксическая ошибка.

Нам нужен способ запуска многострочной команды с использованием одного вызова оболочки.К сожалению, make делает это излишне сложным.

Одно из возможных решений:

SHELL = /bin/bash

...
        @bash -c $$'cd ${ADIR}/exe; shopt -s extglob\nrm -rf !(BDIR)'

Это говорит make использовать bash для выполнения всех рецептов (не /bin/sh).Затем мы снова запускаем bash вручную, но используя $'...', чтобы заключить в строку команды.Это позволяет нам писать \n для встраивания буквального перевода строки, что заставляет extglob / !( ... ) работать.

Нам нужно удвоить $$, чтобы экранировать $ для make, поэтому $'...' становится $$'...'.

Я не очень доволен этим решением.

...