Sie können dies erreichen, indem Sie die Formatierung der alten / neuen / unveränderten Zeilen in der GNU- diffAusgabe steuern :
diff --new-line-format="" --unchanged-line-format="" file1 file2
Die Eingabedateien sollten sortiert sein, damit dies funktioniert. Mit bash(und zsh) können Sie direkt mit der Prozessersetzung sortieren <( ):
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
In den obigen Abschnitten werden neue und unveränderte Zeilen unterdrückt, sodass nur geänderte (in Ihrem Fall entfernte Zeilen) ausgegeben werden. Sie können auch ein paar verwenden diffOptionen , die anderen Lösungen nicht bieten, wie -iFall zu ignorieren, oder verschiedene Leerzeichen Optionen ( -E, -b, -vusw.) für weniger strenges Matching.
Erläuterung
Die Optionen --new-line-format, --old-line-formatund --unchanged-line-formatlassen Sie die Art und Weise steuern , diffformatiert die Unterschiede ähnlich printfFormatbezeichner. Diese Optionen formatieren neue (hinzugefügte), alte (entfernte) bzw. unveränderte Zeilen. Wenn Sie "leer" setzen, wird die Ausgabe dieser Art von Zeile verhindert.
Wenn Sie mit dem einheitlichen Diff- Format vertraut sind , können Sie es teilweise neu erstellen mit:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
Der %LBezeichner ist die betreffende Zeile, und wir stellen jeweils "+" "-" oder "" voran diff -u
(beachten Sie, dass nur Unterschiede ausgegeben werden --- +++und die @@Zeilen und oben bei jeder gruppierten Änderung fehlen ). Sie können dies auch verwenden, um andere nützliche Dinge zu tun, z. B. die Nummerierung jeder Zeile mit %dn.
Die diffMethode (zusammen mit anderen Vorschlägen commund join) erzeugt nur die erwartete Ausgabe mit sortierter Eingabe, obwohl Sie sie <(sort ...)zum Sortieren verwenden können. Hier ist ein einfaches awk(nawk) Skript (inspiriert von den in Konsoleboxs Antwort verknüpften Skripten), das willkürlich geordnete Eingabedateien akzeptiert und die fehlenden Zeilen in der Reihenfolge ausgibt, in der sie in Datei1 vorkommen.
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
Dies speichert den gesamten Inhalt von Datei1 Zeile für Zeile in einem Zeilennummern-indizierten Array ll1[]und den gesamten Inhalt von Datei2 Zeile für Zeile in einem Zeileninhalt-indizierten assoziativen Array ss2[]. Nachdem beide Dateien gelesen wurden, wiederholen Sie den Vorgang ll1und verwenden Sie den inOperator, um festzustellen, ob die Zeile in Datei1 in Datei2 vorhanden ist. (Dies hat eine andere Ausgabe als die diffMethode, wenn Duplikate vorhanden sind.)
Für den Fall, dass die Dateien so groß sind, dass das Speichern beider Dateien ein Speicherproblem verursacht, können Sie die CPU gegen Speicher tauschen, indem Sie nur Datei1 speichern und Übereinstimmungen während des Lesens von Datei2 löschen.
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
Oben wird der gesamte Inhalt von Datei1 in zwei Arrays gespeichert, von denen eines nach Zeilennummer ll1[]und eines nach Zeileninhalt indiziert ist ss1[]. Beim Lesen von Datei2 wird dann jede übereinstimmende Zeile aus ll1[]und gelöscht ss1[]. Am Ende werden die verbleibenden Zeilen aus Datei1 ausgegeben, wobei die ursprüngliche Reihenfolge beibehalten wird.
In diesem Fall können Sie mit dem angegebenen Problem auch mithilfe von GNU (Filterung ist eine GNU-Erweiterung) teilen und siegensplit , wiederholte Läufe mit Blöcken von Datei1 ausführen und Datei2 jedes Mal vollständig lesen:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
Beachten Sie die Verwendung und Platzierung der -Bedeutung stdinin der gawkBefehlszeile. Dies wird von splitaus Datei1 in Blöcken von 20000 Zeilen pro Aufruf bereitgestellt .
Für Benutzer auf nicht-GNU - Systemen gibt an Sicherheit grenzender Wahrscheinlichkeit ist ein GNU coreutils Paket , das Sie erhalten, auf OSX auch im Rahmen der Apple - Xcode - Tool , das GNU bietet diff, awkallerdings nur ein POSIX / BSD spliteher als eine GNU - Version.
awk 'NR==FNR{a[$0];next}!($0 in a)' file2 file1 > out.txt