Как я могу использовать синтаксис Bash в целях Makefile?

Я часто нахожу очень полезным синтаксис Bash , например, замену процесса, как в diff <(sort file1) <(sort file2) .

Можно ли использовать такие команды Bash в Makefile? Я думаю примерно так:

file-differences:
    diff <(sort file1) <(sort file2) > [email protected]

В моем GNU Make 3.80 это приведет к ошибке, поскольку для выполнения команд он использует shell вместо bash .

Ответов (6)

Решение

Из документации GNU Make,

5.3.1 Choosing the Shell
------------------------

The program used as the shell is taken from the variable `SHELL'.  If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.

Так что поместите SHELL := /bin/bash в начало вашего make-файла, и все будет в порядке.

Кстати: вы также можете сделать это для одной цели, по крайней мере, для GNU Make. Каждая цель может иметь свои собственные назначения переменных, например:

all: a b

a:
    @echo "a is $$0"

b: SHELL:=/bin/bash   # HERE: this is setting the shell for b only
b:
    @echo "b is $$0"

Это напечатает:

a is /bin/sh
b is /bin/bash

См. «Целевые значения переменных» в документации для получения более подробной информации. Эта строка может располагаться в любом месте Makefile, не обязательно непосредственно перед целью.

Есть способ сделать это без явной установки вашей переменной SHELL, указывающей на bash. Это может быть полезно, если у вас много make-файлов, поскольку SHELL не наследуется последующими make-файлами и не берется из среды. Вы также должны быть уверены, что любой, кто компилирует ваш код, настраивает свою систему таким образом.

Если вы запустите sudo dpkg-reconfigure dash и ответите «нет» на приглашение, ваша система не будет использовать тире в качестве оболочки по умолчанию. Затем он укажет на bash (по крайней мере, в Ubuntu). Обратите внимание, что использование тире в качестве системной оболочки немного более эффективно.

Один из способов, который также работает, - это поместить его в первую строку вашей цели:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"

Вы можете позвонить bash напрямую, используя -c флаг:

bash -c "diff <(sort file1) <(sort file2) > [email protected]"

Конечно, вы не сможете перенаправить на переменную $ @, но когда я попытался сделать это, у меня появилось -bash: [email protected]: ambiguous redirect сообщение об ошибке, поэтому вы можете изучить это, прежде чем слишком углубляться в это (хотя я используя bash 3.2.something, так что, возможно, ваш работает по-другому).

Вы можете вызвать bash прямо в Makefile вместо использования оболочки по умолчанию:

bash -c "ls -al"

вместо того:

ls -al

Если важна переносимость, возможно, вы не захотите зависеть от конкретной оболочки в вашем Makefile. Не во всех средах доступен bash.