Wie kann ich die Bash-Syntax in Makefile-Zielen verwenden?

208

Ich finde die Bash- Syntax oft sehr hilfreich, z. B. Prozessersetzung wie in diff <(sort file1) <(sort file2).

Ist es möglich, solche Bash-Befehle in einem Makefile zu verwenden? Ich denke an so etwas:

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

In meinem GNU Make 3.80 gibt dies einen Fehler aus, da das shellanstelle von verwendet wird bash, um die Befehle auszuführen.

Frank
quelle
Das war genau mein Problem, ich habe mindestens eine Stunde gebraucht, um diese Frage zu finden! Ich hinterlasse hier meine Fehlermeldung, damit zukünftige Leser sie finden können: /bin/sh: -c: line 0: syntax error near unexpected token ('`
David

Antworten:

380

Aus der GNU Make-Dokumentation,

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.

So legte SHELL := /bin/bashan der Spitze Ihrer Make - Datei, und Sie sollten gut zu gehen.

Übrigens: Sie können dies auch für ein Ziel tun, zumindest für GNU Make. Jedes Ziel kann seine eigenen Variablenzuweisungen haben, wie folgt:

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"

Das wird gedruckt:

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

Weitere Informationen finden Sie in der Dokumentation unter "Zielspezifische Variablenwerte". Diese Zeile kann überall im Makefile stehen, sie muss nicht unmittelbar vor dem Ziel stehen.

derobert
quelle
43
500 Kopfgeld warten auf ein Zitat von man. Sprechen Sie über Timings. : P
SiddharthaRT
3
@inLoveWithPython Nun, infoeigentlich, aber ich denke, es hat Andy wirklich geholfen. Ich weiß, ich hatte
solche
3
Im Zweifelsfall meinte @derobert wörtlich: SHELL=/bin/bashals erste Zeile des Makefiles (oder direkt nach dem Kommentar).
Yauhen Yakimovich
1
Dank @derobert mein Problem dadurch gelöst stackoverflow.com/questions/26806832/...
Chandan Choudhury
2
Ist es möglich, die SHELL-Variable nur für ein bestimmtes Make-Ziel zu ändern, die anderen jedoch unberührt zu lassen?
antred
18

Sie können bashdirekt anrufen , verwenden Sie die -cFlagge:

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

Natürlich können Sie möglicherweise nicht zur Variablen $ @ umleiten, aber als ich dies versuchte, wurde -bash: $@: ambiguous redirecteine Fehlermeldung angezeigt. Vielleicht möchten Sie dies prüfen, bevor Sie sich ebenfalls damit befassen (obwohl ich es bin) mit bash 3.2.something, also funktioniert deins vielleicht anders).

Chris Lutz
quelle
4

Wenn Portabilität wichtig ist, möchten Sie möglicherweise nicht von einer bestimmten Shell in Ihrem Makefile abhängig sein. Nicht in allen Umgebungen ist Bash verfügbar.

Menno Smits
quelle
4

Sie können bash direkt in Ihrem Makefile aufrufen, anstatt die Standard-Shell zu verwenden:

bash -c "ls -al"

anstatt:

ls -al
paxdiablo
quelle
1
Beachten Sie, dass makeder Wert der Umgebungsvariablen SHELL ignoriert wird.
Choroba
2

Es gibt eine Möglichkeit, dies zu tun, ohne Ihre SHELL-Variable explizit so einzustellen, dass sie auf Bash zeigt. Dies kann nützlich sein, wenn Sie viele Makefiles haben, da SHELL nicht von nachfolgenden Makefiles geerbt oder aus der Umgebung übernommen wird. Sie müssen auch sicherstellen, dass jeder, der Ihren Code kompiliert, sein System auf diese Weise konfiguriert.

Wenn Sie sudo dpkg-reconfigure dashdie Eingabeaufforderung ausführen und mit "Nein" antworten, verwendet Ihr System den Bindestrich nicht als Standard-Shell. Es wird dann auf Bash zeigen (zumindest in Ubuntu). Beachten Sie, dass die Verwendung von dash als System-Shell etwas effizienter ist.

Bill G.
quelle
1
Beim Aufrufen unter dem Namen shwird bash im Kompatibilitätsmodus ( set -o posix) ausgeführt. Die vom OP zu verwendende Funktionalität Prozesssubstitution ist in diesem Modus nicht verfügbar.
Charles Duffy
1

Eine Möglichkeit, die auch funktioniert, besteht darin, sie in die erste Zeile Ihres Ziels zu setzen:

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