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 -s
aber es hat nicht funktioniert. Die Reihenfolge ist egal, wichtig ist, dass ich nur den Unterschied sehen möchte, kein > oder < oder Leerzeichen.
grep -FvF
hat 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 -3
bedeutet, 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 grep
mit bash
Prozesssubstitution:
$ 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 derbash
Prozesssubstitutionsmustergrep -vFf test2.csv test1.csv
wird die Zeilen finden, die nur fürtest1.csv
grep -vFf test1.csv test2.csv
wird die Zeilen finden, die nur fürtest2.csv
Abschließend fassen wir die Ergebnisse zusammen durch
cat
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 awk
oder 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 sortierentest1.csv
undtest2.csv
uniq -u
: druckt nur die Zeilen, die keine Duplikate haben