Ich habe eine sehr komfortable Möglichkeit, mein Projekt über einige Zeilen mit Bash-Befehlen zu kompilieren. Aber jetzt muss ich es über Makefile kompilieren. In Anbetracht der Tatsache, dass jeder Befehl in einer eigenen Shell ausgeführt wird, ist meine Frage, wie man einen mehrzeiligen Bash-Befehl, der voneinander abhängig ist, am besten in einem Makefile ausführt. Zum Beispiel so:
for i in `find`
do
all="$all $i"
done
gcc $all
Kann jemand erklären, warum selbst einzeilige Befehle bash -c 'a=3; echo $a > file'
im Terminal korrekt funktionieren, aber im Makefile-Fall eine leere Datei erstellen?
Antworten:
Sie können einen Backslash für die Zeilenfortsetzung verwenden. Beachten Sie jedoch, dass die Shell den gesamten Befehl in einer einzigen Zeile verkettet empfängt. Sie müssen daher auch einige Zeilen mit einem Semikolon abschließen:
Wenn Sie jedoch nur die gesamte vom
find
Aufruf zurückgegebene Liste übernehmen und an übergeben möchten,gcc
benötigen Sie nicht unbedingt einen mehrzeiligen Befehl:Oder verwenden Sie einen eher konventionellen
$(command)
Ansatz (beachten Sie jedoch die$
Flucht):quelle
Wie in der Frage angegeben, wird jeder Unterbefehl in einer eigenen Shell ausgeführt . Dies macht das Schreiben von nicht trivialen Shell-Skripten etwas chaotisch - aber es ist möglich! Die Lösung besteht darin, Ihr Skript so zu konsolidieren, dass make einen einzelnen Unterbefehl (eine einzelne Zeile) berücksichtigt.
Tipps zum Schreiben von Shell-Skripten in Makefiles:
$
durch Ersetzen durch$$
;
zwischen Befehle einfügen\
set -e
der Übereinstimmung von make, um bei einem Unterbefehlsfehler abzubrechen()
oder{}
um die Kohäsivität einer mehrzeiligen Sequenz zu klammern - dies ist keine typische Makefile-BefehlssequenzHier ist ein vom OP inspiriertes Beispiel:
quelle
SHELL := /bin/bash
in Ihrem Makefile auch BASH-spezifische Funktionen wie die Prozessersetzung aktivieren .{
ist entscheidend, um die Interpretation{set
als unbekannter Befehl zu verhindern .{}
und()
macht einen großen Unterschied, wenn Sie das Skript manchmal kopieren und direkt über eine Shell-Eingabeaufforderung ausführen möchten. Sie können Ihre Shell-Instanz verwüsten, indem Sie Variablen deklarieren und insbesondere den Statusset
innerhalb von ändern{}
.()
verhindert, dass das Skript Ihre Umgebung ändert, was wahrscheinlich bevorzugt wird. Beispiel ( dies beendet Ihre Shell-Sitzung ) :{ set -e ; } ; false
.command ; ## my comment \` (the comment is between
einfügen : ; `und` \ `). Dies scheint gut zu funktionieren, außer dass, wenn Sie den Befehl manuell ausführen (durch Kopieren und Einfügen), der Befehlsverlauf den Kommentar so enthält, dass der Befehl unterbrochen wird (wenn Sie versuchen, ihn wiederzuverwenden). [Hinweis: Die Syntaxhervorhebung ist für diesen Kommentar aufgrund der Verwendung von Backslash im Backtick unterbrochen.]Was ist falsch daran, nur die Befehle aufzurufen?
Und für Ihre zweite Frage müssen Sie dem entkommen,
$
indem Sie$$
stattdessen verwenden, dhbash -c '... echo $$a ...'
.BEARBEITEN: Ihr Beispiel könnte wie folgt in ein einzeiliges Skript umgeschrieben werden:
quelle
Der richtige Weg, ein Makefile zu schreiben, besteht natürlich darin, tatsächlich zu dokumentieren, welche Ziele von welchen Quellen abhängen. Im trivialen Fall wird die vorgeschlagene Lösung von sich selbst
foo
abhängen, ist aber natürlichmake
klug genug, um eine zirkuläre Abhängigkeit aufzuheben. Wenn Sie Ihrem Verzeichnis jedoch eine temporäre Datei hinzufügen, wird diese "auf magische Weise" Teil der Abhängigkeitskette. Es ist besser, ein für alle Mal eine explizite Liste von Abhängigkeiten zu erstellen, möglicherweise über ein Skript.GNU make weiß, wie man
gcc
eine ausführbare Datei aus einer Reihe von.c
und.h
Dateien erstellt, also beträgt alles, was Sie wirklich brauchen, vielleichtquelle
Mit der ONESHELL-Direktive können mehrere Zeilenrezepte geschrieben werden, die in demselben Shell-Aufruf ausgeführt werden sollen.
Es gibt jedoch einen Nachteil: Sonderpräfixzeichen ('@', '-' und '+') werden unterschiedlich interpretiert.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
quelle