Как я могу использовать синтаксис 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.

Ответ 1

Из документации 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 вверху вашего файла makefile, и вам должно быть хорошо идти.

BTW: вы также можете сделать это для одной цели, по крайней мере для 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, она не должна быть непосредственно перед целью.

Ответ 2

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

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

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

Ответ 3

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

bash -c "ls -al"

вместо:

ls -al

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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