jede einzelne Zeile in der ersten Datei gegen alle Zeilen in der zweiten Datei differenzieren?

475
IDLacrosseplayer

Ich habe 2 TCL-Darstellungen eines Projekts, die von zwei verschiedenen Versionen desselben Werkzeugs generiert werden, nennen wir sie v1.tclundv2.tcl

Diese Protokolle sind normalerweise logisch identisch, mit Ausnahme der Reihenfolge der Zeilen. Jede Zeile v1.tclwird irgendwo genau einmal gefunden, v2.tclwenn die Versionen 1 und 2 meines Projekts identisch sind.

Ich möchte in der Lage sein zu erkennen, ob jemand eine Änderung vorgenommen hat v2.tcl, auf die zurückgeschickt werden muss v1.tcl(oder umgekehrt) ... mit anderen Worten, ich möchte nur die Zeilen sehen, in denen keine Übereinstimmung besteht. Zum Beispiel:

  1. v1.tcl:

    foo1 bar1 hello1 world1 
  2. v2.tcl:

    hello1 bar1 foo2 world1 goodbye2 
  3. Rückgabewert "diff":

    file1:1 foo1 file2:3 foo2 file2:5 goodbye2 

Soll ich einfach mein eigenes kleines Skript schreiben? Gibt es ein Werkzeug, das dies bereits tut?

2
@PimpJuiceIT Ich bin müde, und da es sich um Code handelt, bekomme ich manchmal Fehler über `grep: Trailing backslash`. Ich werde die Manpages prüfen, um zu sehen, ob ich sie als Text behandeln kann ... IDLacrosseplayer vor 6 Jahren 0
@PimpJuiceIT laufen gerade "grep -vf v2.tcl v1.tcl" -Fehler mit "nachlaufendem Backslash", auch wenn ich es irgendwo wie oben weiterleiten möchte. IDLacrosseplayer vor 6 Jahren 0
@PimpJuiceIT Wenn die Eingabedateien Zeilen mit Backslashes haben, gibt grep die nachfolgenden Backslash-Fehler aus. Ich habe grep's "-F" verwendet, um diese zu korrigieren, und fügte Ihren viel kürzeren Kommentar / Antwort an meinem Ende hinzu. Zu Ihrer Information Ich habe nicht die gesamte awk-Lösung verwendet, sondern bash / cut / grep hinzugefügt, um den Dateinamen und die Zeilen anzuzeigen Xen2050 vor 6 Jahren 1
@ Xen2050 Sehr schöne Lösung, gute Erklärung zu allem. Ich hatte kein Linux zu ssh, um mich unter Linux zu testen, also tat ich das grep, das ich über Windows GNU-Pakete oder was auch immer kommentierte. Pimp Juice IT vor 6 Jahren 0

1 Antwort auf die Frage

5
Xen2050

Wenn die Zeilen identisch sind und Sie nur wissen möchten, ob in der einen oder anderen Datei zusätzliche Zeilen vorhanden sind, können Sie sort & diff (und hier die Prozessersetzung) verwenden:

$ diff -B <(sort v1.tcl) <(sort v2.tcl) 2c2,3 < foo1 --- > foo2 > goodbye2 

Mit diffs -B, um leere Zeilen zu ignorieren. Sie könnten dann verwenden grep -n [pattern] filezu finden, welche Linie das Muster an (vielleicht mit einer oder einer Kombination aus ist grep, cut, sed, awk), wenn es ankommt.

Hier ist eine vollständigere Antwort, die die Datei und die Zeilennummer mit Übereinstimmungen zeigt. Verwendet nicht sed oder awk, nur bash, cut, grep ... hier ist alles (im Wesentlichen) in einer Zeile:

diff -B <(sort v1.tcl) <(sort v2.tcl) | while read -r line; do if \ echo "$line" | grep -q "^<"; then grep -F -n -H \ "$(echo "$line"|cut -c3-)" v1.tcl ; elif echo "$line" | grep -q \ "^>"; then grep -F -n -H "$(echo "$line"|cut -c3-)" v2.tcl ; fi done 

Oder in mehrere Zeilen aufgeteilt:

diff -B <(sort v1.tcl) <(sort v2.tcl) | while read -r line do if echo "$line" | grep -q "^<" then grep -F -n -H "$(echo "$line"|cut -c3-)" v1.tcl elif echo "$line" | grep -q "^>" then grep -F -n -H "$(echo "$line"|cut -c3-)" v2.tcl fi done 

Und abhängig von Ihren Eingabedateien (besonders wenn Sie Zeilen mit nachgestellten Backslashes haben), verwende ich diese Optionen für read & grep:

  • read -r Erlaube keine Backslashes, um Zeichen zu entkommen
  • grep -F Interpretieren Sie PATTERN als eine Liste fester Zeichenfolgen (anstelle von regulären Ausdrücken), die durch Zeilenumbrüche getrennt sind, von denen jede abgeglichen werden muss

Wenn Sie die Kommentare von Pimp Juice IT verwenden, erhalten Sie, wenn nachfolgende umgekehrte Schrägstriche zu Zeilen in den Eingabedateien vorhanden sind, den Fehler "file: line Trailing backslash". Wenn Sie die -FOption für grep verwenden, um den nachfolgenden Backslash-Fehler zu löschen, führt dies zu einer viel kleineren Lösung, die nur für grep gilt:

grep -FvHn -f v2.tcl v1.tcl ;grep -FvHn -f v1.tcl v2.tcl 

Verwendete Optionen von grep:

  • -f Muster von FILE erhalten, eines pro Zeile.
  • -F Interpretieren Sie PATTERN als eine Liste fester Zeichenfolgen (anstelle von regulären Ausdrücken), die durch Zeilenumbrüche getrennt sind, von denen jede abgeglichen werden muss
  • -v Kehren Sie den Sinn der Übereinstimmung um, um nicht übereinstimmende Linien auszuwählen.
  • -H Drucken Sie den Dateinamen für jede Übereinstimmung
  • -n Stellen Sie jeder Zeile der Ausgabe die 1-basierte Zeilennummer in ihrer Eingabedatei voran.
Willkommen :) Die nachfolgenden Backslashes verursachten Probleme mit meinem ersten Entwurf (kein "-F" und ich denke, "-r") antworten auch, obwohl der Beispieltext in Ordnung war und zusätzliche Leerzeilen auch seltsame Probleme verursachten. Aber jetzt scheint alles gut zu sein Xen2050 vor 6 Jahren 0