Wenn die Dateien sortiert sind (in Ihrem Beispiel):
comm -23 file1 file2
-23
unterdrückt die Zeilen, die sich in beiden Dateien oder nur in Datei 2 befinden. Wenn die Dateien nicht sortiert sind, leiten Sie sie durch sort
zuerst...
Sehen Sie sich die Manpage hier an
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
zurück
A
C
Wie funktioniert es?
NR==FNR{a[$0];next}
Idiom dient zum Speichern der ersten Datei in einem assoziativen Array als Schlüssel für einen späteren "Contains"-Test.
NR==FNR
prüft, ob wir die erste Datei scannen, wobei der globale Zeilenzähler (NR) gleich dem Zeilenzähler der aktuellen Datei (FNR) ist.
a[$0]
fügt die aktuelle Zeile als Schlüssel zum assoziativen Array hinzu, beachten Sie, dass sich dies wie eine Menge verhält, bei der es keine doppelten Werte (Schlüssel) gibt
!($0 in a)
wir sind jetzt in der/den nächsten Datei(en), in
ist ein Contains-Test, hier wird überprüft, ob die aktuelle Zeile in der Menge ist, die wir im ersten Schritt aus der ersten Datei !
gefüllt haben negiert die Bedingung. Was hier fehlt, ist die Aktion, die standardmäßig {print}
ist und normalerweise nicht explizit geschrieben.
Beachten Sie, dass dies jetzt verwendet werden kann, um Wörter auf der schwarzen Liste zu entfernen.
$ awk '...' badwords allwords > goodwords
mit einer kleinen Änderung kann es mehrere Listen bereinigen und bereinigte Versionen erstellen.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
Eine andere Möglichkeit, dasselbe zu tun (erfordert auch eine sortierte Eingabe):
join -v 1 fileA fileB
In Bash, wenn die Dateien nicht vorsortiert sind:
join -v 1 <(sort fileA) <(sort fileB)
grep -Fvxf <lines-to-remove> <all-lines>
- funktioniert mit nicht sortierten Dateien (im Gegensatz zu
comm
) - hält die Ordnung ein
- ist POSIX
Beispiel:
cat <<EOF > A
b
1
a
0
01
b
1
EOF
cat <<EOF > B
0
1
EOF
grep -Fvxf B A
Ausgabe:
b
a
01
b
Erklärung:
-F
:Verwenden Sie Literal-Strings anstelle des Standard-BRE-x
:Nur Übereinstimmungen berücksichtigen, die mit der gesamten Zeile übereinstimmen-v
:print non-matching-f file
:Muster aus der gegebenen Datei nehmen
Diese Methode ist bei vorsortierten Dateien langsamer als andere Methoden, da sie allgemeiner ist. Wenn es auch auf die Geschwindigkeit ankommt, siehe:Schneller Weg, Zeilen in einer Datei zu finden, die in einer anderen nicht sind?
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-Upstream.
Verwendung:
remove-lines lines-to-remove remove-from-this-file
Siehe auch:https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another