¿Cómo puedo usar la sintaxis de Bash en los objetivos de Makefile?

209

A menudo encuentro que la sintaxis de Bash es muy útil, por ejemplo, la sustitución de procesos como en diff <(sort file1) <(sort file2).

¿Es posible usar tales comandos Bash en un Makefile? Estoy pensando en algo como esto:

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

En mi GNU Make 3.80, esto dará un error, ya que usa el en shelllugar de bashejecutar los comandos.

Franco
fuente
Este fue exactamente mi problema, ¡me llevó al menos una hora encontrar esta pregunta! Dejo mi mensaje de error aquí para que los futuros lectores puedan encontrarlo: /bin/sh: -c: line 0: syntax error near unexpected token (''
David

Respuestas:

381

De la documentación de 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.

Así que ponlo SHELL := /bin/bashen la parte superior de tu archivo MAKE y estarás listo para comenzar.

Por cierto: también puede hacer esto para un objetivo, al menos para GNU Make. Cada objetivo puede tener sus propias asignaciones variables, como esta:

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"

Eso imprimirá:

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

Consulte "Valores variables específicos del objetivo" en la documentación para obtener más detalles. Esa línea puede ir a cualquier parte del Makefile, no tiene que estar inmediatamente antes del objetivo.

derobert
fuente
43
500 recompensas esperando una cotización de man. Habla sobre los tiempos. : P
SiddharthaRT
3
@inLoveWithPython Bueno, en inforealidad, pero supongo que realmente ayudó a Andy. Sé que he tenido días así ...
derobert 03 de
3
en caso de duda, @derobert significaba literalmente: SHELL=/bin/bashcomo la primera línea del Makefile (o justo después del comentario).
Yauhen Yakimovich
1
Gracias @derobert resolvió mi problema en stackoverflow.com/questions/26806832/…
Chandan Choudhury
2
¿Es posible cambiar la variable SHELL solo para un objetivo de marca en particular pero dejar los otros intactos?
antred
18

Puedes llamar bashdirectamente, usa la -cbandera:

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

Por supuesto, es posible que no pueda redirigir a la variable $ @, pero cuando intenté hacer esto, obtuve -bash: $@: ambiguous redirect un mensaje de error, por lo que es posible que desee ver eso antes de que también lo haga (aunque estoy usando bash 3.2.algo, así que tal vez el tuyo funcione de manera diferente).

Chris Lutz
fuente
4

Si la portabilidad es importante, es posible que no desee depender de un shell específico en su Makefile. No todos los entornos tienen bash disponible.

Menno Smits
fuente
4

Puede llamar a bash directamente dentro de su Makefile en lugar de usar el shell predeterminado:

bash -c "ls -al"

en vez de:

ls -al
paxdiablo
fuente
1
Tenga en cuenta que makeignora el valor de la variable de entorno SHELL.
choroba
2

Hay una manera de hacer esto sin configurar explícitamente su variable SHELL para que apunte a bash. Esto puede ser útil si tiene muchos archivos MAKE ya que SHELL no se hereda de los archivos MAKE posteriores ni se toma del entorno. También debe asegurarse de que cualquiera que compile su código configure su sistema de esta manera.

Si ejecuta sudo dpkg-reconfigure dashy responde 'no' a la solicitud, su sistema no usará el guión como el shell predeterminado. Luego apuntará a bash (al menos en Ubuntu). Sin embargo, tenga en cuenta que usar dash como el shell de su sistema es un poco más eficiente.

Bill G
fuente
1
Cuando se invoca bajo el nombre sh, bash se ejecuta en modo de compatibilidad ( set -o posix). La funcionalidad que el OP está tratando de usar, la sustitución del proceso, no está disponible en este modo.
Charles Duffy
1

Una forma que también funciona es ponerlo de esta manera en la primera línea de su objetivo:

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