Як я можу використовувати синтаксис Bash у цілях Makefile?


208

Я часто вважаю синтаксисом Баша дуже корисним, наприклад, підміна процесу, як у diff <(sort file1) <(sort file2).

Чи можливо використовувати такі команди Bash у Makefile? Я думаю про щось подібне:

file-differences:
    diff <(sort file1) <(sort file2) > $@

У моєму GNU Make 3.80 це призведе до помилки, оскільки він використовує shellзамість того, bashщоб виконувати команди.


Це була саме моя проблема, мені знадобилося принаймні одну годину, щоб знайти це питання! Я залишаю тут повідомлення про помилку, щоб майбутні читачі могли його знайти: /bin/sh: -c: line 0: syntax error near unexpected token (''
Девід

Відповіді:


380

З документації 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 у верхній частині свого файлового файлу, і вам слід добре піти.

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, це не повинно бути безпосередньо перед ціллю.


43
500 баунті чекають цитати від man. Поговоріть про таймінги. : P
SiddharthaRT

3
@inLoveWithPython Ну, infoнасправді, але, я думаю, це дійсно допомогло Енді. Я знаю, що у мене були такі дні ...
derobert

3
якщо сумніваєтесь, @derobert мав на увазі буквально: SHELL=/bin/bashяк перший рядок Makefile (або відразу після коментаря).
Яуген Якимович

1
Спасибі @derobert вирішив мою проблему в stackoverflow.com/questions/26806832/…
Chandan Choudhury

2
Чи можливо змінити змінну SHELL лише для однієї конкретної цілі, а інші залишити недоторканими?
antred

18

Ви можете телефонувати bashбезпосередньо, використовувати -cпрапор:

bash -c "diff <(sort file1) <(sort file2) > $@"

Звичайно, ви, можливо, не зможете перенаправити на змінну $ @, але коли я спробував це зробити, я отримав -bash: $@: ambiguous redirectповідомлення про помилку, тож ви, можливо, захочете розібратися в цьому, перш ніж ви занадто вдаритесь до цього (хоча я використовуючи bash 3.2.щось, тож, можливо, ваша працює інакше).


4

Якщо портативність важлива, ви, можливо, не захочете залежати від конкретної оболонки у вашому Makefile. Не у всіх середовищах доступний удар.


4

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

bash -c "ls -al"

замість:

ls -al

1
Зауважте, що makeігнорує значення змінної середовища SHELL.
choroba

2

Існує спосіб зробити це без явного встановлення змінної SHELL, щоб вона вказувала на баш. Це може бути корисно, якщо у вас є багато файлів, оскільки SHELL не успадковується наступними файлами або виймається з оточення. Ви також повинні бути впевнені, що кожен, хто компілює ваш код, налаштовує свою систему таким чином.

Якщо запустити sudo dpkg-reconfigure dashвідповідь на відповідь "ні", система не використовуватиме тире як оболонку за замовчуванням. Тоді він вкаже на баш (принаймні, в Ubuntu). Зауважте, що використання тире як системної оболонки трохи ефективніше.


1
При виклику під іменем shbash працює в режимі сумісності ( set -o posix). Функціонал, який OP намагається використовувати, підміна процесу, недоступна в цьому режимі.
Чарльз Даффі

1

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

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.