Ich habe eine große Datei A (bestehend aus E-Mails), eine Zeile für jede Mail. Ich habe auch eine andere Datei B , die einen anderen Satz von Mails enthält.
Mit welchem Befehl würde ich alle in Datei B angezeigten Adressen aus Datei A entfernen.
Wenn also Datei A enthält:
A
B
C
und Datei B enthalten:
B
D
E
Dann sollte Datei A belassen werden mit:
A
C
Jetzt weiß ich, dass dies eine Frage ist, die möglicherweise häufiger gestellt wurde, aber ich habe nur einen Befehl online gefunden , der mir einen Fehler mit einem schlechten Trennzeichen gegeben hat.
Jede Hilfe wäre sehr dankbar! Jemand wird sich sicherlich einen cleveren Einzeiler einfallen lassen, aber ich bin kein Shell-Experte.
Antworten:
Wenn die Dateien sortiert sind (in Ihrem Beispiel):
-23
Unterdrückt die Zeilen in beiden Dateien oder nur in Datei 2. Wenn die Dateien nicht sortiert sind, leiten Sie siesort
zuerst durch ...Siehe die Manpage hier
quelle
comm -23 file1 file2 > file3
gibt Inhalte in Datei1 aus, nicht in Datei2, in Datei3. Undmv file3 file1
würde dann endlich redundante Inhalte in Datei1 löschen.comm -23 file1 file2 | sponge file1
. Keine Bereinigung erforderlich.grep -Fvxf <lines-to-remove> <all-lines>
Beispiel:
Ausgabe:
Erläuterung:
-F
: Verwenden Sie Literalzeichenfolgen anstelle der Standard-BRE-x
: Berücksichtigen Sie nur Übereinstimmungen, die mit der gesamten Zeile übereinstimmen-v
: Druck nicht übereinstimmend-f file
: Nehmen Sie Muster aus der angegebenen DateiDiese Methode ist bei vorsortierten Dateien langsamer als bei anderen Methoden, da sie allgemeiner ist. Wenn auch Geschwindigkeit wichtig ist, siehe: Schnelle Suche nach Zeilen in einer Datei, die sich nicht in einer anderen befinden?
Hier ist eine schnelle Bash-Automatisierung für den Inline-Betrieb:
remove-lines() ( remove_lines="$1" all_lines="$2" tmp_file="$(mktemp)" grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file" mv "$tmp_file" "$all_lines" )
GitHub stromaufwärts .
Verwendung:
Siehe auch: /unix/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another
quelle
awk zur Rettung!
Diese Lösung erfordert keine sortierten Eingaben. Sie müssen zuerst fileB bereitstellen.
awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA
kehrt zurück
Wie funktioniert es?
Beachten Sie, dass dies jetzt zum Entfernen von Wörtern auf der schwarzen Liste verwendet werden kann.
$ awk '...' badwords allwords > goodwords
Mit einer geringfügigen Änderung können mehrere Listen bereinigt und bereinigte Versionen erstellt werden.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
quelle
A\nC
, schreibe zuerst in eine temporäre Datei und überschreibe die Originaldatei... > tmp && mv tmp fileA
fileB
nicht leer ist (0 Byte lang). Andernfalls wird anstelle des erwarteten Inhalts von ein leeres Ergebnis angezeigtfileA
. (Ursache:FNR==NR
giltfileA
dann.)Eine andere Möglichkeit, dasselbe zu tun (erfordert auch sortierte Eingaben):
Wenn die Dateien in Bash nicht vorsortiert sind:
quelle
Sie können dies tun, es sei denn, Ihre Dateien sind sortiert
diff file-a file-b --new-line-format="" --old-line-format="%L" --unchanged-line-format="" > file-a
--new-line-format
ist für Zeilen, die in Datei b, aber nicht in a sind,--old-..
ist für Zeilen, die in Datei a, aber nicht in b sind,--unchanged-..
ist für Zeilen, die in beiden sind.%L
macht es so, dass die Linie genau gedruckt wird.für mehr Details
quelle
comm
Befehlen vorschlug .comm
erfordert, dass die Dateien sortiert werden. Wenn sie also sortiert sind, können Sie diese Lösung auch verwenden. Sie können diese Lösung verwenden, unabhängig davon, ob die Datei sortiert ist oder nichtDiese Verfeinerung der netten Antwort von @ karakfa kann bei sehr großen Dateien spürbar schneller sein. Wie bei dieser Antwort muss keine Datei sortiert werden, aber die Geschwindigkeit wird durch die assoziativen Arrays von awk sichergestellt. Nur die Suchdatei wird gespeichert.
Diese Formulierung ermöglicht auch die Möglichkeit, dass nur ein bestimmtes Feld ($ N) in der Eingabedatei für den Vergleich verwendet werden soll.
# Print lines in the input unless the value in column $N # appears in a lookup file, $LOOKUP; # if $N is 0, then the entire line is used for comparison. awk -v N=$N -v lookup="$LOOKUP" ' BEGIN { while ( getline < lookup ) { dictionary[$0]=$0 } } !($N in dictionary) {print}'
(Ein weiterer Vorteil dieses Ansatzes besteht darin, dass das Vergleichskriterium leicht geändert werden kann, z. B. um führende und nachfolgende Leerzeichen zu kürzen.)
quelle
Sie können Python verwenden:
python -c ' lines_to_remove = set() with open("file B", "r") as f: for line in f.readlines(): lines_to_remove.add(line.strip()) with open("file A", "r") as f: for line in [line.strip() for line in f.readlines()]: if line not in lines_to_remove: print(line) '
quelle
Sie können verwenden -
diff fileA fileB | grep "^>" | cut -c3- > fileA
Dies funktioniert für Dateien, die nicht ebenfalls sortiert sind.
quelle
Um gemeinsame Zeilen zwischen zwei Dateien zu entfernen, können Sie den Befehl grep, comm oder join verwenden.
Dies zeigt Zeilen aus Datei1 an, die mit keiner Zeile in Datei2 übereinstimmen.
Dies zeigt Zeilen aus Datei1 an, die mit keiner Zeile in Datei2 übereinstimmen.
quelle