Frage Wie kann ich diff erhalten, um nur hinzugefügte und gelöschte Zeilen anzuzeigen? Wenn diff das nicht kann, welches Werkzeug kann das?


Wie kann ich diff erhalten, um nur hinzugefügte und gelöschte Zeilen anzuzeigen? Wenn diff das nicht kann, welches Werkzeug kann das?


60
2017-09-25 12:47


Ursprung


Sie müssen besser definieren, was Sie mit hinzugefügt und gelöscht meinen. Kann sich eine Zeile ändern? Wenn ja, wie soll eine geänderte Zeile gehandhabt werden? Wenn Sie streng linienorientierte Prüfungen durchführen, ist eine Zeilenänderung identisch mit der alten Zeile, die entfernt wird, und der neuen Zeile, die hinzugefügt wird. Zum Beispiel, wie sollte es mit einer Linie umgehen, die in zwei Teile geteilt ist? Wie zwei 1 Zeile geändert? 2 Zeilen geändert? 1 Zeile entfernt und 2 Zeilen hinzugefügt? Wenn Sie nicht garantieren können, dass sich Zeilen niemals ändern, einfach hinzugefügt und gelöscht werden, denke ich, dass dies ohne bessere Definitionen zum Scheitern verurteilt ist. - Christopher Cashell
Ich finde die Frage ziemlich unklar. Aber zumindest eine Interpretation der Frage konnte mit beantwortet werden diff A B | grep '^[<>]' - kasperd
Sie suchen vielleicht comm. - Jenny D
@ChristopherCashell, Er bedeutet ignorieren Sortierreihenfolge; ein typisch häufiges Problem. Normalerweise wird dies getan, indem zuerst die Segmente (Linien) auf jeder Seite sortiert werden, bevor ein typisches Diff durchgeführt wird. - Pacerier
@Pacierier, bist du dir da sicher? Oder raten Sie? Nichts über Sortierung oder Suchreihenfolge wird in der Frage erwähnt oder angedeutet. So wie es aussieht, ist die Frage nicht klar und könnte auf viele verschiedene Arten interpretiert werden. Ohne zu wissen sicher Was er verlangt, wir machen Annahmen und bieten Lösungen an, die das eigentliche Problem lösen können oder auch nicht. Darüber hinaus deutet der Kommentar des ursprünglichen Posters auf eine der Antworten darauf hin nicht im Zusammenhang mit dem Sortieren. Es hat mit der Bedeutung von "hinzugefügt und gelöscht" vs. "geändert" zu tun. - Christopher Cashell


Antworten:


Eine andere Art, es zu betrachten:

Zeilen anzeigen, die nur in Datei a vorhanden sind: (d. H. Was aus a gelöscht wurde)

comm -23 a b

Zeige Zeilen, die nur in Datei b vorhanden sind (d. H. Was zu b hinzugefügt wurde)

comm -13 a b

Zeige Zeilen, die nur in der einen oder der anderen Datei existieren: (aber nicht beides)

comm -3 a b | sed 's/^\t//'

(Warnung: Wenn Datei a hat Zeilen, die mit TAB beginnen, wird (die erste TAB) aus der Ausgabe entfernt.)

HINWEIS: Beide Dateien müssen nach "comm" sortiert werden, damit sie ordnungsgemäß funktionieren. Wenn sie nicht bereits sortiert sind, sollten Sie sie sortieren:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

Wenn die Dateien extrem lang sind, kann dies eine ziemliche Belastung sein, da sie eine zusätzliche Kopie und somit doppelt so viel Speicherplatz benötigt.


73
2017-09-25 18:11



wollte nur hinzufügen, dass beide Dateien sortiert werden müssen (Groß- / Kleinschreibung beachten), damit diese Lösung korrekte Ergebnisse liefert - marmor
Auf modern genug Muscheln können Sie in-line mit etwas wie sortieren comm -12 <(sort a) <(sort b) - Joshua Huber


comm könnte tun, was du willst. Von seiner Manpage:

BESCHREIBUNG

Vergleichen Sie die sortierten Dateien FILE1 und FILE2 Zeile für Zeile.

Ohne Optionen, erzeugen Sie drei Spalten. Spalte eins   enthält Zeilen, die für FILE1, Spalte eindeutig sind   Zwei enthält Zeilen, die für FILE2 eindeutig sind.   und Spalte drei enthält Linien gemeinsam   zu beiden Dateien.

Diese Spalten sind unterdrückbar mit -1, -2 und -3 beziehungsweise.

Beispiel:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

Und wenn Sie nur die einzigartigen Linien wollen und sich nicht darum kümmern, in welcher Datei sie sich befinden:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

Wie die Manpage sagt, müssen die Dateien vorher sortiert werden.


12
2017-09-25 14:27





Um Zusätze und Löschungen ohne Kontext anzuzeigen, Zeilennummern, +, -, <,>! usw., können Sie diff wie folgt verwenden:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Zum Beispiel, zwei Dateien gegeben:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

Der folgende Befehl zeigt Zeilen an, die entweder aus a entfernt oder zu b hinzugefügt wurden:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Ausgabe:

B-ONLY
A-ONLY

Dieser etwas andere Befehl zeigt die Zeilen, die aus a.txt entfernt wurden:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

Ausgabe:

A-ONLY

Schließlich zeigt dieser Befehl Zeilen, die zu a.txt hinzugefügt wurden

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

Ausgabe

B-ONLY

8
2018-01-05 06:41





Das ist, was Diff standardmäßig tut ... Vielleicht müssen Sie einige Flags hinzufügen, um Whitespace zu ignorieren?

diff -b -B

sollte leere Zeilen und unterschiedliche Anzahl von Leerzeichen ignorieren.


2
2017-09-25 13:26



Nein, es werden auch CHANGED-Zeilen angezeigt (Zeilen, die ein Zeichen oder vier verschiedene Zeichen haben). Ich möchte Zeilen, die nur links oder rechts existieren. - C. Ross
Man könnte argumentieren, dass die unterschiedlichen Versionen einer CHANGED-Datei jeweils nur links oder rechts existieren. - markdrayton
Es gibt keine Möglichkeit für diff (oder ein anderes Tool), zuverlässig zu erkennen, was eine Änderung ist und was eine gelöschte Zeile durch eine neue Zeile ersetzt. - Cian
Technisch behandelt diff eine "geänderte" Zeile so, als ob die ursprüngliche Zeile gelöscht worden wäre und eine neue Zeile hinzugefügt wurde ... also technisch zeigt sie nur hinzugefügte und gelöschte Zeilen an. - KFro


Nein, diff zeigt nicht wirklich die Unterschiede zwischen zwei Dateien in der Art, wie man denken könnte. Es erzeugt eine Sequenz von Bearbeitungsbefehlen für ein Werkzeug wie patch um eine Datei in eine andere zu ändern.

Die Schwierigkeit für jeden Versuch, das zu tun, wonach Sie suchen, besteht darin, zu definieren, was eine Linie ausmacht, die sich gegenüber einer gelöschten ändert, gefolgt von einer hinzugefügten Linie. Auch was zu tun ist, wenn Zeilen hinzugefügt, gelöscht und nebeneinander geändert werden.


2
2017-09-25 15:59



Genau meine Gedanken. Wie viel Prozent der Zeichen in einer Zeile müssen geändert werden, um sie als eine neue anstelle einer Änderung des Originals zu betrachten? Technisch gesehen, selbst wenn Sie ein gemeinsames Zeichen haben, könnten Sie es als "Änderung" betrachten, anstatt es zu löschen und einzufügen. - Kamil Kisiel
Es ist lange her, seit ich auf die diff Quellen, aber ich erinnere mich an alle Arten von Drehungen, um zu verfolgen, wo zwei Dateien zusammenpassen, um synchron zu bleiben, und ich denke, es gibt eine Schwelle, um aufzugeben, je nachdem, wie weit die Zeilen auseinander liegen. Aber ich erinnere mich nicht an eine Intra-Line-Übereinstimmung, außer für (optional) zusammengebrochenen Leerraum oder ignorierenden Fall. Oder (vielleicht) Worte zu diesem Effekt. Auf jeden Fall geht es darum patchund "Vgrep" kommt nur für die Fahrt. Könnte sein. Am Dienstag. - Dennis Williamson


Visuelle Vergleichstools passen zwei Dateien zusammen, so dass ein Segment mit der gleichen Anzahl von Zeilen, aber unterschiedlichen Inhalts als ein geändertes Segment betrachtet wird. Völlig neue Zeilen zwischen übereinstimmenden Segmenten werden als hinzugefügte Segmente betrachtet.

Das ist auch wie sdiff Das Befehlszeilentool funktioniert, das einen direkten Vergleich zweier Dateien in einem Terminal anzeigt. Geänderte Zeilen sind durch | getrennt Charakter. Wenn eine Zeile nur in Datei A vorhanden ist, wird <als Trennzeichen verwendet. Wenn eine Zeile nur in Datei B existiert, wird> als Trennzeichen verwendet. Wenn Sie keine <und> Zeichen in den Dateien haben, können Sie damit nur zusätzliche Zeilen anzeigen:

sdiff A B | grep '[<>]'

2
2017-10-17 14:34





Danke senarvi, deine Lösung (nicht gewählt) gab mir tatsächlich genau das, was ich wollte, nachdem ich eine Ewigkeit auf einer Menge Seiten gesucht habe.

Ich benutze Ihre Antwort, hier ist, was ich gefunden habe, um die Liste der Dinge zu bekommen, die geändert / hinzugefügt / gelöscht wurden. Das Beispiel verwendet 2 Versionen der Datei / etc / passwd und gibt den Benutzernamen für die relevanten Datensätze aus.

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'

2
2017-11-18 12:05



Beachten Sie, dass der Unterschied zwischen "eine Zeile wurde geändert" und "eine Zeile wurde entfernt und Ein weiterer Zeile wurde unterhalb oder darüber hinzugefügt "ist semantisch. Ein generisches textbasiertes Diff-Tool kann diese Fälle nicht trennen. Daher kann Ihre sdiff-basierte Antwort nicht in allen Fällen zuverlässig funktionieren. - Mikko Rantalainen