Warum schlägt diff fehl, wenn es von einem Makefile aus aufgerufen wird?

7

Eingrenzen eines Patch-Problems, das ich zu beheben versuche: Nur zwei Dateien mit einer Größe von jeweils 1 Byte:

  • Datei a(enthält 'a')
  • Datei b(enthält 'b') und

Ziel ist es, einen Patch zu erstellen und dann anzuwenden, der den Wert von 'b'in ändert 'a'. Inhalt von Makefile sind:

patch:
        diff -u b a > b2a.patch
        patch -o b.corrected b < b2a.patch
        diff a b.corrected

clean:
        rm -f b2a.patch b.corrected

In Anbetracht des oben makeGesagten schlägt mit der folgenden Ausgabe fehl:

$ make
diff -u b a > b2a.patch
make: *** [patch] Error 1

Wenn ich jedoch die Befehle im Makefile nacheinander auf der Bash-Shell ausführe, gibt es überhaupt kein Problem.

Marcus Junius Brutus
quelle
1
was ist die exit codevon , diffwenn Sie es manuell ausführen?
umläute
@umlaute es ist 1
Marcus Junius Brutus
@umlaute ok also das Ersetzen von 'diff' durch '-diff' behebt es - es war eine Makefile-Sache
Marcus Junius Brutus
Ich weiß nicht, warum Sie den Patch erstellen und dann sofort anwenden möchten ... z. B. warum nicht einfach verwenden cp? Da dies nicht wirklich sinnvoll ist, gehe ich davon aus, dass dies ein vereinfachter Testfall ist.
Derobert
@derobert deine annahme ist richtig. Ich notiere das zu Beginn meines Beitrags ("Narrow-down ..")
Marcus Junius Brutus

Antworten:

11

Make geht davon aus, dass ein Exit-Code von 0 Erfolg bedeutet, alles andere bedeutet Misserfolg. Dies ist die Standardkonvention, die von fast allen Befehlszeilentools verwendet wird.

Ist leider diffkeiner von denen. Wenn Sie die GNU Diff-Infoseite und auch den Eintrag "Diff" der Single Unix Specification überprüfen , bedeutet 0, dass keine Unterschiede gefunden wurden, 1 bedeutet, dass Unterschiede gefunden wurden, und ≥2 bedeutet, dass ein Fehler vorliegt.

Sie können Make anweisen, den Beendigungsstatus vollständig zu ignorieren, indem Sie dem Befehl einen Bindestrich voranstellen, wie Sie es in Ihrem Kommentar getan haben. Dadurch werden jedoch tatsächliche Fehler ignoriert - wahrscheinlich nicht das, was Sie möchten. Stattdessen können Sie:

patch:
        diff -u b a > b2a.patch; [ $$? -eq 1 ]
        patch -o b.corrected b < b2a.patch
        diff a b.corrected; [ $$? -eq 1 ]

Beachten Sie das ; [ $$? -eq 1 ]Bit, das ich am Ende der beiden Diff-Linien hinzugefügt habe. Sie können ; test $$? -eq 1natürlich auch verwenden. Die $?Shell-Variable ist $$?auf normale Makefile-Escape-Konventionen zurückzuführen. Beachten Sie, dass dies auch den Exit-Status 0 (keine Unterschiede) ablehnt, was wahrscheinlich das ist, was Sie wollen.

Übrigens: Es scheint, dass dies wirklich sein sollte:

patch: b.corrected
        diff …
b.corrected: b2a.patch
        patch …
b2a.patch: a b
        diff …

so dass Änderungen von a und b übernommen und die Dateien korrekt neu generiert werden.

derobert
quelle
@ Bananguin Danke für die Bearbeitung, das ist wahrscheinlich wahr. Ich bin nicht ganz sicher, was OP zu erreichen versucht ...
derobert
Eigentlich fühlte ich mich einfach schlecht, weil deine Version nicht falsch war, nur eine Ecke zu viel für mich vor dem Abendessen.
Trotzdem
Die Unix-Konvention für Rückkehrcodes ist etwas breiter als "0 für Erfolg,> 0 für Fehler". Für Befehle, die ein boolesches Ergebnis zurückgeben, lautet die Konvention "0 für Ja, 1 für Nein,> 1 für Fehler". diffist ein Beispiel dafür, wie sind grep, test...
‚SO- Anschlag, die bösen‘ Gilles
@ Gilles Nun, diffwürde fragen " Sind diese Dateien unterschiedlich?" ... Wohl ist diff rückwärts. Aber ich denke, sowohl es als auch cmpbeide geben 0 für Match zurück, 1 für Unterschied.
Derobert
@derobert diffund cmpfragen Sie " Sind diese Dateien identisch?"
Gilles 'SO - hör auf böse zu sein'