find_duplicate_lines.bat
Erstellt einen Duplikatbericht und eine bereinigte UTF-8-Datei, wobei die Reihenfolge der ersten Vorkommen erhalten bleibt.
Finden und bereinigenPrüfen Sie, ob eine TXT-Datei wiederholte Zeilen enthält, erstellen Sie eine bereinigte Kopie ohne Duplikate, behalten Sie die ursprüngliche Reihenfolge bei, vermeiden Sie UTF-8-Codierungsprobleme oder verwenden Sie PowerShell und die Eingabeaufforderung für manuelle Prüfungen.
Die einfachste wiederverwendbare Methode ist das BAT-Skript aus Methode 1. Ziehen Sie eine TXT-Datei darauf, um sowohl einen Duplikatbericht als auch eine bereinigte Kopie ohne wiederholte Zeilen zu erstellen. Die Originaldatei wird nicht verändert. Für eine schnelle Prüfung ausschließlich in der Konsole verwenden Sie den folgenden PowerShell-Befehl:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Ersetzen Sie input.txt durch den tatsächlichen Dateinamen. Dieser Befehl meldet nur Duplikate; er erstellt keine bereinigte Datei. Die Option -Encoding UTF8 ist in Windows PowerShell 5.1 wichtig, da eine UTF-8-Datei ohne Byte Order Mark andernfalls möglicherweise mit der Windows-ANSI-Codepage decodiert wird.
-CaseSensitive behandelt Server und server als unterschiedliche Zeilen. Entfernen Sie diese Option, wenn die Groß-/Kleinschreibung ignoriert werden soll.
РіС...enthält, wurde die Datei mit der falschen Codierung gelesen. Behalten Sie -Encoding UTF8 für UTF-8-Dateien bei. Verwenden Sie -Encoding Default für eine ältere ANSI-Datei oder -Encoding Unicode für UTF-16-Text im Little-Endian-Format.
Erstellt einen Duplikatbericht und eine bereinigte UTF-8-Datei, wobei die Reihenfolge der ersten Vorkommen erhalten bleibt.
Finden und bereinigenZeigt jede wiederholte Zeile und die Anzahl ihrer Vorkommen an, kann bei sehr großen Dateien jedoch langsam sein.
Schneller BerichtOrdnet identische Zeilen direkt untereinander an, meldet oder entfernt Duplikate jedoch nicht automatisch.
Kleine DateienEine doppelte Zeile ist eine Zeile, deren Vergleichswert in derselben Datei mehr als einmal vorkommt. Das Ergebnis hängt jedoch von den gewählten Vergleichsregeln ab.
| Zeilen | Exakter Vergleich | Vergleich ohne Beachtung der Groß-/Kleinschreibung |
|---|---|---|
Windows und Windows |
Duplikat | Duplikat |
Windows und windows |
Unterschiedlich | Duplikat |
example und example |
Wegen des nachgestellten Leerzeichens unterschiedlich | Weiterhin unterschiedlich, sofern Leerzeichen nicht entfernt werden |
| Zwei leere Zeilen | Doppelte Leerzeile | Doppelte Leerzeile |
Verwenden Sie für eine strikte Prüfung einen Vergleich unter Beachtung der Groß-/Kleinschreibung und entfernen Sie keine Leerzeichen. Bei Listen mit Namen, URLs, Domains oder Kennungen kann es sinnvoll sein, die Groß-/Kleinschreibung sowie versehentliche Leerzeichen am Anfang oder Ende einer Zeile zu ignorieren.
Verwenden Sie für wiederholte Prüfungen find_duplicate_lines.bat als BAT-Skript. Ziehen Sie eine Textdatei darauf oder geben Sie den vollständigen Pfad ein. Das Skript erstellt im selben Ordner zwei UTF-8-Dateien:
filename_duplicates.txt — ein Bericht mit jeder wiederholten Zeile und ihrer Gesamtanzahl.filename_without_duplicates.txt — eine bereinigte Kopie, in der nur das erste Vorkommen jeder Zeile erhalten bleibt.find_duplicate_lines.bat in das Feld für den Dateinamen ein.@echo off
setlocal EnableExtensions DisableDelayedExpansion
title Find and Remove Duplicate Lines in a Text File
set "INPUT_FILE=%~1"
if not defined INPUT_FILE (
echo Drag a text file onto this BAT file, or enter its full path below.
echo.
set /p "INPUT_FILE=Text file path: "
)
if not defined INPUT_FILE (
echo.
echo No file was selected.
pause
exit /b 1
)
for %%I in ("%INPUT_FILE%") do set "INPUT_FILE=%%~fI"
if not exist "%INPUT_FILE%" (
echo.
echo File not found:
echo %INPUT_FILE%
pause
exit /b 1
)
for %%I in ("%INPUT_FILE%") do (
set "DUPLICATE_FILE=%%~dpnI_duplicates.txt"
set "CLEAN_FILE=%%~dpnI_without_duplicates.txt"
)
echo.
echo Processing:
echo %INPUT_FILE%
echo.
set "FD_SCRIPT_FILE=%~f0"
set "FD_INPUT_FILE=%INPUT_FILE%"
set "FD_DUPLICATE_FILE=%DUPLICATE_FILE%"
set "FD_CLEAN_FILE=%CLEAN_FILE%"
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$content=[IO.File]::ReadAllText($env:FD_SCRIPT_FILE); $marker=':'+'POWERSHELL'; $code=$content.Substring($content.IndexOf($marker)+$marker.Length); & ([ScriptBlock]::Create($code)) -Path $env:FD_INPUT_FILE -DuplicatePath $env:FD_DUPLICATE_FILE -CleanPath $env:FD_CLEAN_FILE"
set "RESULT=%ERRORLEVEL%"
echo.
if "%RESULT%"=="0" (
echo Finished. Two files were created:
echo Duplicate report:
echo %DUPLICATE_FILE%
echo.
echo File without duplicate lines:
echo %CLEAN_FILE%
) else if "%RESULT%"=="2" (
echo Finished. No exact duplicate lines were found.
echo The cleaned copy was still created:
echo %CLEAN_FILE%
) else (
echo The file could not be processed.
)
echo.
pause
exit /b %RESULT%
:POWERSHELL
param(
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $true)]
[string]$DuplicatePath,
[Parameter(Mandatory = $true)]
[string]$CleanPath
)
$ErrorActionPreference = 'Stop'
function Get-TextEncodingInfo {
param([string]$FilePath)
$stream = [System.IO.File]::OpenRead($FilePath)
try {
$bom = New-Object byte[] 4
$read = $stream.Read($bom, 0, 4)
}
finally {
$stream.Dispose()
}
if ($read -ge 4 -and
$bom[0] -eq 0x00 -and $bom[1] -eq 0x00 -and
$bom[2] -eq 0xFE -and $bom[3] -eq 0xFF) {
return [PSCustomObject]@{
Encoding = [System.Text.Encoding]::GetEncoding(12001)
AllowAnsiFallback = $false
}
}
if ($read -ge 4 -and
$bom[0] -eq 0xFF -and $bom[1] -eq 0xFE -and
$bom[2] -eq 0x00 -and $bom[3] -eq 0x00) {
return [PSCustomObject]@{
Encoding = [System.Text.Encoding]::UTF32
AllowAnsiFallback = $false
}
}
if ($read -ge 3 -and
$bom[0] -eq 0xEF -and $bom[1] -eq 0xBB -and
$bom[2] -eq 0xBF) {
return [PSCustomObject]@{
Encoding = New-Object System.Text.UTF8Encoding($true)
AllowAnsiFallback = $false
}
}
if ($read -ge 2 -and $bom[0] -eq 0xFF -and $bom[1] -eq 0xFE) {
return [PSCustomObject]@{
Encoding = [System.Text.Encoding]::Unicode
AllowAnsiFallback = $false
}
}
if ($read -ge 2 -and $bom[0] -eq 0xFE -and $bom[1] -eq 0xFF) {
return [PSCustomObject]@{
Encoding = [System.Text.Encoding]::BigEndianUnicode
AllowAnsiFallback = $false
}
}
return [PSCustomObject]@{
Encoding = New-Object System.Text.UTF8Encoding($false, $true)
AllowAnsiFallback = $true
}
}
function Read-And-CleanTextFile {
param(
[string]$FilePath,
[System.Text.Encoding]$Encoding,
[string]$TemporaryCleanPath
)
$comparer = [System.StringComparer]::Ordinal
$counts = New-Object 'System.Collections.Generic.Dictionary[string,int]' ($comparer)
$seen = New-Object 'System.Collections.Generic.HashSet[string]' ($comparer)
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
$reader = New-Object System.IO.StreamReader($FilePath, $Encoding, $true)
$writer = New-Object System.IO.StreamWriter($TemporaryCleanPath, $false, $utf8WithBom)
$totalLines = 0
try {
while (($line = $reader.ReadLine()) -ne $null) {
$totalLines++
if ($seen.Add($line)) {
$writer.WriteLine($line)
}
$count = 0
if ($counts.TryGetValue($line, [ref]$count)) {
$counts[$line] = $count + 1
}
else {
$counts.Add($line, 1)
}
}
}
finally {
$reader.Dispose()
$writer.Dispose()
}
return [PSCustomObject]@{
Counts = $counts
TotalLines = $totalLines
UniqueLines = $seen.Count
}
}
$tempCleanPath = Join-Path ([System.IO.Path]::GetDirectoryName($CleanPath)) ([System.IO.Path]::GetRandomFileName())
try {
$encodingInfo = Get-TextEncodingInfo -FilePath $Path
try {
$data = Read-And-CleanTextFile -FilePath $Path -Encoding $encodingInfo.Encoding -TemporaryCleanPath $tempCleanPath
}
catch [System.Text.DecoderFallbackException] {
if (-not $encodingInfo.AllowAnsiFallback) {
throw
}
if (Test-Path -LiteralPath $tempCleanPath) {
Remove-Item -LiteralPath $tempCleanPath -Force
}
$data = Read-And-CleanTextFile -FilePath $Path -Encoding ([System.Text.Encoding]::Default) -TemporaryCleanPath $tempCleanPath
}
if (Test-Path -LiteralPath $CleanPath) {
Remove-Item -LiteralPath $CleanPath -Force
}
Move-Item -LiteralPath $tempCleanPath -Destination $CleanPath
$duplicates = @(
$data.Counts.GetEnumerator() |
Where-Object { $_.Value -gt 1 } |
Sort-Object Key
)
if ($duplicates.Count -eq 0) {
if (Test-Path -LiteralPath $DuplicatePath) {
Remove-Item -LiteralPath $DuplicatePath -Force
}
Write-Host ("Lines read: {0}" -f $data.TotalLines)
Write-Host ("Unique lines written: {0}" -f $data.UniqueLines)
exit 2
}
$report = New-Object System.Collections.Generic.List[string]
$report.Add("Count`tLine")
foreach ($duplicate in $duplicates) {
$report.Add(("{0}`t{1}" -f $duplicate.Value, $duplicate.Key))
}
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllLines($DuplicatePath, $report, $utf8WithBom)
Write-Host ("Lines read: {0}" -f $data.TotalLines)
Write-Host ("Unique lines written: {0}" -f $data.UniqueLines)
Write-Host ("Duplicate groups found: {0}" -f $duplicates.Count)
exit 0
}
catch {
if (Test-Path -LiteralPath $tempCleanPath) {
Remove-Item -LiteralPath $tempCleanPath -Force
}
Write-Error $_.Exception.Message
exit 1
}
find_duplicate_lines.bat. Alternativ können Sie auf die BAT-Datei doppelklicken und den vollständigen Pfad zur Textdatei einfügen.filename_duplicates.txt , um wiederholte Zeilen und die Anzahl ihrer Vorkommen anzuzeigen.filename_without_duplicates.txt , um die bereinigte Liste ohne zusätzliche Duplikatvorkommen zu erhalten.| Datei | Sortierverhalten | Inhalt |
|---|---|---|
filename_duplicates.txt |
Alphabetisch nach der doppelten Zeile sortiert | Ein Eintrag pro doppeltem Wert einschließlich Gesamtanzahl |
filename_without_duplicates.txt |
Nicht sortiert; die ursprüngliche Reihenfolge bleibt erhalten | Nur das erste Vorkommen jeder exakt übereinstimmenden Zeile |
| Ursprüngliche TXT-Datei | Weder sortiert noch verändert | Bleibt unverändert |
Count Line
4 example.com
2 server-01
Windows und windows werden als unterschiedliche Zeilen behandelt.PowerShell liest die Datei als Sammlung einzelner Zeilen. -Encoding UTF8 weist Windows PowerShell 5.1 an, eine UTF-8-Datei korrekt zu decodieren, einschließlich UTF-8-Dateien ohne Byte Order Mark. Group-Object gruppiert identische Zeilen, und Where-Object behält nur Gruppen bei, die mehr als ein Element enthalten.
powershellein und drücken Sie Enter.input.txt durch Ihren Dateinamen ersetzt haben.Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Count Name
----- ----
4 example.com
3 192.168.1.10
2 Windows 11
Dieses Ergebnis bedeutet, dass example.com viermal vorkommt, 192.168.1.10 dreimal vorkommt und Windows 11 zweimal vorkommt.
Sie können dieselbe Prüfung aus jedem Ordner ausführen, indem Sie den vollständigen Pfad angeben:
Get-Content -LiteralPath "C:\Users\User\Desktop\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
-LiteralPath ist vorzuziehen, wenn ein Dateiname Zeichen wie eckige Klammern enthält, da PowerShell den Pfad exakt wie angegeben behandelt. In den Beispielen wird -Encoding UTF8verwendet; ersetzen Sie diesen Parameter durch die passende Codierungsangabe, wenn die Quelldatei nicht in UTF-8 vorliegt.
Verwenden Sie diese Variante, wenn Sie nur wissen möchten, ob mindestens eine wiederholte Zeile vorhanden ist:
$duplicate = Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object -First 1
if ($null -ne $duplicate) {
Write-Host "Duplicate lines found."
} else {
Write-Host "No duplicate lines found."
}
Der Befehl gibt nur die erste Duplikatgruppe zurück. PowerShell muss die Datei dennoch vollständig lesen und gruppieren, bevor das Ergebnis ausgegeben werden kann. Dies ist in einem Skript, einer geplanten Aufgabe oder einem wiederholbaren Prüfablauf nützlich.
if (Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 | Group-Object -CaseSensitive | Where-Object Count -gt 1 | Select-Object -First 1) { "Duplicate lines found" } else { "No duplicate lines found" }
Um den Duplikatbericht zu speichern, statt ihn nur in der Konsole anzuzeigen, exportieren Sie die gruppierten Ergebnisse in eine CSV-Datei:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, @{Name="Line"; Expression={$_.Name}} |
Export-Csv -LiteralPath ".\duplicate-report.csv" -NoTypeInformation -Encoding UTF8
Die Ausgabedatei duplicate-report.csv kann in Excel, LibreOffice Calc, im Editor oder in einem anderen Texteditor geöffnet werden.
Verwenden Sie den folgenden Befehl, wenn Sie eine einfache TXT-Datei benötigen, die jede zuvor doppelte Zeile nur einmal enthält:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
ForEach-Object Name |
Set-Content -LiteralPath ".\duplicate-lines.txt" -Encoding UTF8
Set-Content , solange dieselbe Pipeline diese Datei noch liest.
Group-Object ignoriert standardmäßig die Groß-/Kleinschreibung. Entfernen Sie -CaseSensitive , damit PC, Pcund pc als derselbe Wert behandelt werden:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object |
Where-Object Count -gt 1 |
Select-Object Count, Name
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
ForEach-Object { $_.Trim() } |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
Dadurch werden example, exampleund example als gleichwertig behandelt. Leerzeichen innerhalb einer Zeile werden nicht entfernt.
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Where-Object { $_.Trim().Length -gt 0 } |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
ForEach-Object { $_.Trim() } |
Where-Object { $_.Length -gt 0 } |
Group-Object |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Der in Windows integrierte Befehl sort.exe kann identische Zeilen direkt untereinander anordnen. Dadurch lassen sich Duplikate leichter manuell erkennen, aber SORT erkennt, zählt oder entfernt wiederholte Zeilen nicht automatisch.
cmdein und drücken Sie Enter.sort "input.txt" /o "sorted.txt"
Öffnen Sie sorted.txt im Editor. Wiederholte Werte stehen anschließend direkt untereinander und können visuell geprüft werden.
Rufen Sie für eine automatische Prüfung aus der Eingabeaufforderung Windows PowerShell über CMD auf. In diesem Beispiel wird UTF-8 außerdem ausdrücklich angegeben, damit kyrillische Zeichen und Akzentzeichen in Windows PowerShell 5.1 nicht als ANSI decodiert werden:
powershell.exe -NoProfile -Command "Get-Content -LiteralPath '.\input.txt' -Encoding UTF8 | Group-Object -CaseSensitive | Where-Object Count -gt 1 | Select-Object Count, Name"
Das BAT-Skript aus Methode 1 ist effizienter als die kurzen Group-Object -Beispiele, da es die vollständige Datei nicht in ein Array einliest und nicht jede Quellzeile alphabetisch sortiert. Es liest sequenziell, schreibt erste Vorkommen direkt in die bereinigte Ausgabe und speichert im Arbeitsspeicher nur die eindeutigen Schlüssel und ihre Zähler.
Die direkten PowerShell-Befehle bleiben praktisch, doch Group-Object kann bei einer großen Datei deutlich langsamer sein und viel Arbeitsspeicher belegen.
Beachten Sie bei großen Dateien folgende Hinweise:
Group-Object.Wenn PowerShell kyrillischen, akzentuierten oder anderen nicht englischen Text als Zeichenfolgen wie РіС...anzeigt, wird die Quelldatei normalerweise mit der falschen Zeichencodierung decodiert. Der Text selbst kann weiterhin intakt sein; das Problem liegt darin, wie Get-Content die Dateibytes interpretiert.
-Encoding UTF8.
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Dies funktioniert in Windows PowerShell 5.1 für UTF-8-Text mit oder ohne Byte Order Mark. In neueren PowerShell-Versionen ist UTF-8 bei vielen Textoperationen normalerweise die Standardeinstellung; eine ausdrückliche Angabe macht den Befehl jedoch eindeutig.
| Codierung der Quelldatei | Get-Content-Parameter | Wann verwenden |
|---|---|---|
| UTF-8 | -Encoding UTF8 |
Empfohlen für moderne TXT-Dateien, einschließlich UTF-8 ohne BOM. |
| Windows-ANSI-Codepage | -Encoding Default |
Für ältere Dateien verwenden, die in der aktuellen Windows-Systemcodepage gespeichert wurden. |
| UTF-16 Little Endian | -Encoding Unicode |
Für UTF-16-LE-Dateien verwenden, die häufig an einem FF FE BOM erkannt werden. |
| UTF-16 Big Endian | -Encoding BigEndianUnicode |
Für UTF-16-BE-Dateien verwenden, die häufig an einem FE FF BOM erkannt werden. |
Get-Content -LiteralPath ".\input.txt" -Encoding Default |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
Get-Content -LiteralPath ".\input.txt" -Encoding Unicode |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
chcp 65001 ändert die Codepage der Konsole, teilt Get-Content jedoch nicht mit, wie die Quelldatei decodiert werden soll. Geben Sie stattdessen -Encoding UTF8 bei Get-Content an.
Das wiederverwendbare Skript find_duplicate_lines.bat in diesem Ratgeber erkennt UTF-8 mit oder ohne BOM, unterstützt UTF-16 und UTF-32 mit BOM und greift auf die Windows-ANSI-Codepage zurück, wenn eine Bytefolge ohne BOM kein gültiges UTF-8 ist. Es speichert sowohl den Duplikatbericht als auch die bereinigte Kopie als UTF-8 mit BOM.
Get-Content, Group-Objectund Select-Object lesen und analysieren die Datei nur, sofern Sie nicht ausdrücklich einen Schreibbefehl hinzufügen, zum Beispiel Set-Content oder Export-Csv.(Get-Content -LiteralPath ".\input.txt" -Encoding UTF8).Countaus. Bei einer sehr großen Datei liest PowerShell die Datei weiterhin vollständig ein, was einige Zeit dauern kann.find_duplicate_lines.bat. Das Skript erstellt automatisch *_without_duplicates.txt und lässt die Quelldatei unverändert. Die bereinigte Ausgabe behält das erste Vorkommen jeder exakt übereinstimmenden Zeile bei.Group-Object ignoriert standardmäßig die Groß-/Kleinschreibung. Fügen Sie -CaseSensitive hinzu, wenn Groß- und Kleinbuchstaben exakt verglichen werden müssen.-Encoding UTF8 direkt nach dem Dateipfad hinzu. Eine Änderung der Konsole mit chcp 65001 allein korrigiert nicht, wie Get-Content die Datei decodiert.find_duplicate_lines.bat liest die ausgewählte Datei und erstellt *_duplicates.txt sowie *_without_duplicates.txt. Die ursprüngliche Textdatei wird niemals überschrieben.Verwenden Sie für wiederholte Prüfungen find_duplicate_lines.bat. Es nimmt eine Datei per Drag-and-drop entgegen, führt einen exakten Vergleich unter Beachtung der Groß-/Kleinschreibung durch, erstellt einen alphabetisch sortierten Duplikatbericht und schreibt eine zweite UTF-8-Datei ohne zusätzliche Duplikatvorkommen, wobei die ursprüngliche Reihenfolge erhalten bleibt.
Verwenden Sie PowerShell mit Get-Content -Encoding UTF8 und Group-Object , wenn Sie nur einen interaktiven Bericht benötigen oder die Vergleichsregeln anpassen möchten. Der Windows-Befehl sort.exe eignet sich nur für die manuelle Prüfung kleiner Dateien.