Unterschied zwischen zwei großen Dateien

Unterschied zwischen zwei großen Dateien

Ich habe "test1.csv" und es enthält

200,400,600,800
100,300,500,700
50,25,125,310

und test2.csv und es enthält

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

Jetzt

diff test2.csv test1.csv > result.csv

ist anders als

diff test1.csv test2.csv > result.csv

Ich weiß nicht, welche die richtige Reihenfolge ist, aber ich möchte etwas anderes. Beide Befehle oben geben ungefähr Folgendes aus:

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

Ich möchte nur die Differenz ausgeben, daher sollte results.csv so aussehen

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Ich habe es versucht diff -q, diff -saber es hat nicht funktioniert. Die Reihenfolge ist egal, wichtig ist, dass ich nur den Unterschied sehen möchte, kein > oder < oder Leerzeichen.

grep -FvFhat bei kleineren Dateien funktioniert, bei großen nicht

Die erste Datei enthält mehr als 5 Millionen Zeilen, die zweite Datei enthält 1300.

results.csv sollte also ~4.998.700 Zeilen ergeben

Ich habe es auch versucht, grep -F -x -v -f aber es hat nicht funktioniert.

Antwort1

Klingt nach einem Job für comm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

Wie erklärt in man comm:

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

Das -3bedeutet, dass nur Zeilen gedruckt werden, die eindeutig in einer der Dateien vorkommen. Diese werden jedoch entsprechend der Datei eingerückt, in der sie gefunden wurden. Um den Tab zu entfernen, verwenden Sie:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

In diesem Fall müssen Sie die Dateien nicht einmal wirklich sortieren und können das oben genannte wie folgt vereinfachen:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

Antwort2

Verwendung grepmit bashProzesssubstitution:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

So speichern Sie die Ausgabe unter results.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()ist derbashProzesssubstitutionsmuster

  • grep -vFf test2.csv test1.csvwird die Zeilen finden, die nur fürtest1.csv

  • grep -vFf test1.csv test2.csvwird die Zeilen finden, die nur fürtest2.csv

  • Abschließend fassen wir die Ergebnisse zusammen durchcat

Oder alsOli hat vorgeschlagen, Sie können auch die Befehlsgruppierung verwenden:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Oder führen Sie einfach einen nach dem anderen aus, da beide an STDOUT schreiben, werden sie letztendlich hinzugefügt:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Antwort3

Wenn die Reihenfolge der Zeilen nicht relevant ist, verwenden Sie awkoder perl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

Verwenden Sie grep, um die gemeinsamen Zeilen zu erhalten und diese herauszufiltern:

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

Das interne Grep ruft die gemeinsamen Zeilen ab, anschließend findet das externe Grep die Zeilen, die nicht mit diesen gemeinsamen Zeilen übereinstimmen.

Antwort4

Da die Reihenfolge nicht beibehalten werden muss, gehen Sie einfach wie folgt vor:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: zusammenführen und sortieren test1.csvundtest2.csv
  • uniq -u: druckt nur die Zeilen, die keine Duplikate haben

verwandte Informationen