Verhindert, dass diff am Ende der Datei nach Zeilenumbrüchen sucht

21

Ich habe zwei große Bäume, die ich vergleichen möchte. Einige der Dateien im Baum unterscheiden sich nur dadurch, dass eine Zeile am Ende einen Zeilenumbruch enthält und die andere Datei diesen Zeilenumbruch nicht enthält. Ich möchte diese Tatsache ignorieren. Ich habe versucht, diffwie folgt anzurufen:

diff --ignore-all-space -r <dir1> <dir2>

Und das funktioniert. Mein Problem ist, dass es auch andere (raumbezogene) Unterschiede ignoriert, die wichtig sein können.

Zusammenfassend: Ich möchte den Zeilenumbruch bei EOF einfach ignorieren. Ist das möglich mit diff?

dangonfast
quelle

Antworten:

17

Grundsätzlich müssen Sie zwei Dateien vergleichen und das nachfolgende Byte unter bestimmten Bedingungen ignorieren. Es gibt keine "diff" -Option, aber es gibt eine Reihe von Möglichkeiten, wie dies gemacht werden kann (z. B. kommt auch hex diff in den Sinn).

Um 'diff' zu verwenden, müssen Sie im Grunde genommen die Dateien ändern, denen die Zeilenumbruchzeile am Ende einer Datei fehlt, und dann vergleichen. Sie können ein temporäres Verzeichnis mit den geänderten Dateien erstellen oder mit ein wenig Skripting im Speicher ausführen. (Was bevorzugt wird, hängt von der Präferenz, der Dateigröße, der Anzahl der Dateien ... ab.)

Beispiel: Der folgende Befehl ändert den Inhalt einer Datei (wird verwendet sed -i, um sie an Ort und Stelle zu ändern. Dies wird nur auf stdout gedruckt.), Um eine neue Zeile hinzuzufügen, falls eine fehlt (oder die Datei unverändert zu lassen, falls bereits eine neue Zeile vorhanden ist):

sed -e '$a\'  file1.txt

Und nur um die 'diff'-Syntax zu überprüfen (true bedeutet, dass sie gleich sind, false bedeutet anders):

$ diff a/file1.txt   b/file1.txt  \
      && echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different

Stellen Sie sicher, dass nur Leerzeichen unterschiedlich sind:

$ diff --ignore-all-space  a/file1.txt   b/file1.txt \
     && echo '** are same' || echo '** are different'
** are same

In bash können wir 'sed' verwenden, um den Dateiinhalt so zu bearbeiten, wie er an 'diff' übergeben wird (Originaldateien bleiben unverändert):

$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
     && echo '** are same' || echo '** are different'
** are same

Jetzt müssen Sie nur noch emulieren diff -r, um Verzeichnisse rekursiv zu vergleichen. Wenn Sie Verzeichnisse aund vergleichen b, leiten Sie für alle Dateien in a(z. B. a/dir1/dir2/file.txt) den Pfad zur Datei in b(z. B. b/dir1/dir2/file.txt) ab und vergleichen Sie:

$ for f in $( find a -type f  )
> do
>    diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done

Eine etwas ausführlichere Version:

$ for f in $( find a -type f  )
> do
>   f1=$f
>   f2=b/${f#*/}
>   echo "compare: $f1 $f2"
>   diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
>       && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same
michael
quelle
Könnten Sie bitte erklären, was sed -e '$a\'genau funktioniert? thx
törzsmókus
Führen Sie sedmit dem folgenden ( -e) Skript / Ausdruck aus, der mit dem Ende der Datei ( $) übereinstimmt , und führen Sie die Aktion "Anhängen" (a \) aus, geben Sie jedoch keinen Text an (nichts nach dem `\`) wird weiterhin eine EOF / Newline am Ende der Datei einfügen (nur wenn diese fehlt).
Michael
Danke. Habe ich noch nicht gesehen a\ .
Törzsmókus
1

Ich habe das Problem gelöst, indem ich jeder Datei eine neue Zeile hinzugefügt und leere Zeilen im Diff ignoriert habe (Option -B). Diese Lösung ist möglicherweise nicht für Ihren Anwendungsfall geeignet, kann jedoch anderen helfen:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 
Jakob
quelle
0

Leiten Sie die Ausgabe von diffan einen grepBefehl weiter, der die Nachricht löscht, die Sie nicht sehen möchten.

David Schwartz
quelle
nicht gut. diff -r existiert mit result! = 0, wenn ich --ignore-all-space nicht hinzufüge. Um es klar auszudrücken: Ich möchte, dass diff Zeilenumbrüche bei EOF ignoriert und nur bei EOF. Und ich möchte, dass ein Ergebnis angezeigt wird, das diesen Kriterien entspricht. Das heißt, wenn sich Dateien im Baum nur in der Newline bei EOF unterscheiden, darf dies nicht als Unterschied angesehen werden und diff muss daher 0 zurückgeben.
dangonfast
0

Ich habe mir auch einen anderen Ansatz überlegt, der für größere Dateien funktioniert (und die Originaldateien immer noch nicht kopiert oder modifiziert). Sie müssten immer noch die rekursive Verzeichnisdurchquerung emulieren (und es gibt eine Reihe von Möglichkeiten, dies zu tun), aber in diesem Beispiel wird nicht "sed" verwendet, sondern nur zwei Dateien ohne das letzte Byte verglichen cmp, z.

$ cmp  a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different

$ du -b a/file1.txt  b/file1.txt 
13  a/file1.txt
12  b/file1.txt

$ cmp  -n 12 a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
** are same

Durchlaufen Sie weiterhin alle Dateien im Verzeichnis, und berechnen Sie für zwei Dateien a / file.txt und b / file.txt die größere Dateigröße, subtrahieren Sie eine und führen Sie dann ein binäres diff ( cmp) mit dieser Anzahl von Bytes aus (ebenfalls in) bash):

(( bytes = $(du -b a/file.txt  b/file.txt  | sort -nr | head -1  | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt

Das Durchlaufen der Dateien erfolgt wie in der anderen Antwort mit sedund diff.

michael
quelle
0

Die Antwort ist einfach.
Die Meldung über den fehlenden Zeilenumbruch befindet sich nicht im Ausgabestream von, diffsondern im Fehlerstrom. Biege es also zum Nirvana und du bist für immer fertig

diff -rqEeB fileA fileB 2> /dev/null
Yunzen
quelle
diff gibt einen Wert! = 0 zurück, wenn es Unterschiede findet und ich diesen Wert überprüfen möchte. Das Umleiten nach / dev / null lässt diff diesen Unterschied nicht vergessen, daher ist der zurückgegebene Wert! = 0, was ich nicht möchte. Ich möchte, dass diff zwei Dateien als gleich betrachtet, wenn der einzige Unterschied der letzte Zeilenumbruch ist
dangonfast
-1

In diff befindet sich eine Flagge --strip-trailing-cr, die genau das tut, wonach Sie gefragt haben

Dharman
quelle
-1. Hast du das versucht? Es behandelt /r/nwie /nund hat nichts mit extra /nkurz vor EOF zu tun .
Kamil Maciorowski
Ich habe das ausprobiert und es verwendet, um Dateien mit verschiedenen DOS / UNIX-Zeilenumbrüchen zu unterscheiden. Ist das nicht richtig?
Dharman
Die Frage bezieht sich nur auf das Ignorieren des Zeilenumbruchs bei EOF (Dateiende).
Kamil Maciorowski