Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden (Windows Powershell Lösung)

Im Post Mehrfache Einträge in großen Konfigurationsdateien oder Protokollen finden(Linux/Unix) habe ich gezeigt, wie mehrfach vorkommende Zeilen in Textdateien gefunden und automatisch entfernt werden können.
Windows hat im Zuge der Powershell ein mächtiges Werkzeug, dass dies auch kann. (Seit dem Windows 10 1709 Update kann man natürlich auch einfach die eingebaute bash nehmen….)

Zur Demonstration verwende ich eine Datei duplicates.txt:

Get-Content -Path duplicates.txt

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor

Mehrfache vorkommende identische Zeilen und deren Anzahl findet und zählt man wie mit Group-Object

Get-Content -Path duplicates.txt |Group-Object

Count Name Group
—– —- —–
1 Zeile kommt nur einmal… {Zeile kommt nur einmal vor}
2 Zeile kommt zweimal vor {Zeile kommt zweimal vor, Zeile kommt zweimal vor}
3 Zeile kommt dreimal vor {Zeile kommt dreimal vor, Zeile kommt dreimal vor, Zeile kommt dreimal vor}
1 Zeile kommt auch nur e… {Zeile kommt auch nur einmal vor}

Wenn die Reihenfolge der Zeilen keine Bedeutung hat, ist es einfach, doppelte oder mehrfache Zeilen zu entfernen:

Get-Content -Path duplicates.txt | Sort-object -Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

oder

Get-Content -Path duplicates.txt | sort-object | Get-Unique

Zeile kommt auch nur einmal vor
Zeile kommt dreimal vor
Zeile kommt nur einmal vor
Zeile kommt zweimal vor

Die Ausgabe aller mehrfach vorkommenden Zeilen kann mit einer einfachen Abfrage geschehen:

Get-Content -Path duplicates.txt | Group | ? { $_.Count -gt 1 } |Select -ExpandProperty Name

Schwieriger wird es, die doppelten Zeilen zu entfernen, wenn die Reihenfolge in der Datei erhalten bleiben soll. Eine Hash Tabelle hilft an dieser Stelle weiter. Die zugrunde liegende Idee ist, für jede Zeile beim ersten Auftreten einen Eintrag in einer Hashtabelle vorzunehmen. Sollte dieser Zeile erneut auftreten, wird sie übersprungen. Das ist der Code:

$hash = $null
$hashTable = @{}
Get-Content .\duplicates.txt | ForEach-Object {
  if ($hashTable.Item($_) -eq $null) {
    $_
    $hashTable.Add($_,”found”)
  }
}

Zeile kommt nur einmal vor
Zeile kommt zweimal vor
Zeile kommt dreimal vor
Zeile kommt auch nur einmal vor

Die ersten beiden Zeilen initialisieren die Tabelle $hashTable. Dann wird für jede neue Zeile ein Eintrag mit dem Wert “found” hinzugefügt (eine 1, ein true oder ähnlich würden es auch tun, Hauptsache ein Eintrag für die Zeile existiert.).

Achtung: Die Ausgabe von $hashTable.Keys gibt die Reihenfolge nicht wie in der Datei aus:

$hashTable.Keys

Zeile kommt dreimal vor
Zeile kommt zweimal vor
Zeile kommt nur einmal vor
Zeile kommt auch nur einmal vor

Sehr hilfreich sind die Erklärungen zu Powershell Hash Tabellen von den Scripting Guys.