find_duplicate_lines.bat
Crea un informe de duplicados y un archivo UTF-8 limpio conservando el orden de las primeras apariciones.
Buscar y limpiarComprueba si un archivo TXT contiene líneas repetidas, crea una copia limpia sin duplicados, conserva el orden original, evita problemas de codificación UTF-8 o utiliza PowerShell y el Símbolo del sistema para realizar comprobaciones manuales.
El método reutilizable más sencillo es el script BAT del Método 1. Arrastra un archivo TXT sobre él para crear tanto un informe de duplicados como una copia limpia sin líneas repetidas. El archivo original no se modifica. Para una comprobación rápida únicamente en la consola, utiliza el siguiente comando de PowerShell:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Sustituye input.txt por el nombre real del archivo. Este comando solo muestra los duplicados; no crea un archivo limpio. La opción -Encoding UTF8 es importante en Windows PowerShell 5.1 porque, de lo contrario, un archivo UTF-8 sin marca de orden de bytes puede descodificarse como la página de códigos ANSI de Windows.
-CaseSensitive considera Server y server como líneas diferentes. Elimina esta opción cuando no quieras distinguir entre mayúsculas y minúsculas.
РіС..., el archivo se leyó con una codificación incorrecta. Mantén -Encoding UTF8 para archivos UTF-8. Utiliza -Encoding Default para un archivo ANSI antiguo o -Encoding Unicode para texto UTF-16 little-endian.
Crea un informe de duplicados y un archivo UTF-8 limpio conservando el orden de las primeras apariciones.
Buscar y limpiarMuestra cada línea repetida y el número de apariciones, aunque puede ser lento con archivos muy grandes.
Informe rápidoColoca las líneas iguales una junto a otra, pero no informa ni elimina los duplicados automáticamente.
Archivos pequeñosUna línea duplicada es aquella cuyo valor de comparación aparece más de una vez en el mismo archivo. Sin embargo, el resultado depende de las reglas de comparación que elijas.
| Líneas | Comparación exacta | Comparación sin distinguir mayúsculas y minúsculas |
|---|---|---|
Windows y Windows |
Duplicado | Duplicado |
Windows y windows |
Diferentes | Duplicado |
example y example |
Diferentes por el espacio final | Siguen siendo diferentes salvo que se eliminen los espacios |
| Dos líneas vacías | Línea en blanco duplicada | Línea en blanco duplicada |
Para una comprobación estricta, utiliza una comparación que distinga mayúsculas y minúsculas y no elimines los espacios. Para listas de nombres, URL, dominios o identificadores, puede resultar preferible ignorar las diferencias de mayúsculas y minúsculas y los espacios accidentales al principio o al final de una línea.
Para comprobaciones repetidas, utiliza el siguiente script find_duplicate_lines.bat . Arrastra un archivo de texto sobre él o introduce la ruta completa. El script crea dos archivos UTF-8 en la misma carpeta:
filename_duplicates.txt — un informe que contiene cada línea repetida y su número total de apariciones.filename_without_duplicates.txt — una copia limpia en la que solo se conserva la primera aparición de cada línea.find_duplicate_lines.bat en el campo de nombre de archivo.@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. También puedes hacer doble clic en el archivo BAT y pegar la ruta completa del archivo de texto.filename_duplicates.txt para ver las líneas repetidas y su número de apariciones.filename_without_duplicates.txt para obtener la lista limpia sin apariciones duplicadas.| Archivo | Comportamiento de ordenación | Contenido |
|---|---|---|
filename_duplicates.txt |
Ordenado alfabéticamente por la línea duplicada | Una entrada por cada valor duplicado, junto con su recuento total |
filename_without_duplicates.txt |
No se ordena; se conserva el orden original | Solo la primera aparición de cada línea exacta |
| Archivo TXT original | No se ordena ni se modifica | Permanece sin cambios |
Count Line
4 example.com
2 server-01
Windows y windows se consideran líneas diferentes.PowerShell lee el archivo como una colección de líneas. -Encoding UTF8 indica a Windows PowerShell 5.1 que descodifique correctamente un archivo UTF-8, incluidos los archivos UTF-8 sin marca de orden de bytes. Group-Object agrupa las líneas iguales, y Where-Object conserva únicamente los grupos que contienen más de un elemento.
powershelly pulsa Introduce.input.txt por el nombre de tu archivo.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
Este resultado significa que example.com aparece cuatro veces, 192.168.1.10 aparece tres veces y Windows 11 aparece dos veces.
Puedes ejecutar la misma comprobación desde cualquier carpeta indicando la ruta completa:
Get-Content -LiteralPath "C:\Users\User\Desktop\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
-LiteralPath es preferible cuando el nombre del archivo contiene caracteres como corchetes, ya que PowerShell interpreta la ruta exactamente como está escrita. Los ejemplos utilizan -Encoding UTF8; sustitúyelo por el parámetro de codificación correcto cuando el archivo de origen no sea UTF-8.
Utiliza esta versión cuando solo necesites saber si existe al menos una línea repetida:
$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."
}
El comando devuelve únicamente el primer grupo duplicado, aunque PowerShell debe leer y agrupar todo el archivo antes de poder generar el resultado. Es útil en un script, una tarea programada o un flujo de validación repetible.
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" }
Para guardar el informe de duplicados en lugar de mostrarlo únicamente en la consola, exporta los resultados agrupados a un archivo CSV:
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
El archivo de salida duplicate-report.csv se puede abrir en Excel, LibreOffice Calc, el Bloc de notas u otro editor de texto.
Utiliza el siguiente comando cuando necesites un archivo TXT sencillo que contenga una copia de cada línea duplicada:
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 mientras la misma canalización todavía está leyendo ese archivo.
Group-Object no distingue entre mayúsculas y minúsculas de forma predeterminada. Elimina -CaseSensitive para considerar PC, Pc, y pc como el mismo valor:
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
Esto hace que example, example, y example sean equivalentes. No elimina los espacios del interior de una línea.
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
El comando integrado de Windows sort.exe puede colocar las líneas idénticas una junto a otra. Esto facilita la identificación manual de duplicados, pero SORT no identifica, cuenta ni elimina automáticamente las líneas repetidas.
cmd y pulsa Enter.sort "input.txt" /o "sorted.txt"
Abre sorted.txt en el Bloc de notas. Los valores repetidos aparecerán uno junto a otro, lo que permite realizar una comprobación visual.
Para realizar una comprobación automática desde el Símbolo del sistema, llama a Windows PowerShell desde CMD. Este ejemplo también especifica UTF-8 de forma explícita para que los caracteres cirílicos y acentuados no se descodifiquen como ANSI en Windows PowerShell 5.1:
powershell.exe -NoProfile -Command "Get-Content -LiteralPath '.\input.txt' -Encoding UTF8 | Group-Object -CaseSensitive | Where-Object Count -gt 1 | Select-Object Count, Name"
El script BAT del Método 1 es más eficiente que los ejemplos breves con Group-Object porque no lee el archivo completo en una matriz ni ordena alfabéticamente todas las líneas del archivo de origen. Realiza una lectura secuencial, escribe las primeras apariciones directamente en la salida limpia y solo almacena en memoria las claves únicas y sus contadores.
Los comandos directos de PowerShell siguen siendo prácticos, pero Group-Object puede ser considerablemente más lento y consumir una gran cantidad de RAM con un archivo grande.
Para un archivo grande, toma las siguientes precauciones:
Group-Object.Si PowerShell muestra texto cirílico, acentuado o de otros idiomas como secuencias del tipo РіС..., normalmente el archivo de origen se está descodificando con una codificación de caracteres incorrecta. El texto puede seguir intacto; el problema es cómo Get-Content interpreta los bytes del archivo.
-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
Esto funciona con texto UTF-8 con o sin marca de orden de bytes en Windows PowerShell 5.1. En las versiones más recientes de PowerShell, UTF-8 suele ser la codificación predeterminada para muchas operaciones de texto, pero especificarla de forma explícita evita ambigüedades.
| Codificación del archivo de origen | Parámetro de Get-Content | Cuándo utilizarlo |
|---|---|---|
| UTF-8 | -Encoding UTF8 |
Recomendado para archivos TXT modernos, incluido UTF-8 sin BOM. |
| Página de códigos ANSI de Windows | -Encoding Default |
Utilízalo para archivos antiguos guardados con la página de códigos actual del sistema Windows. |
| UTF-16 little-endian | -Encoding Unicode |
Utilízalo para archivos UTF-16 LE, que suelen identificarse mediante una BOM FF FE BOM. |
| UTF-16 big-endian | -Encoding BigEndianUnicode |
Utilízalo para archivos UTF-16 BE, que suelen identificarse mediante una BOM FE FF BOM. |
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 cambia la página de códigos de la consola, pero no indica a Get-Content cómo descodificar el archivo de origen. Especifica -Encoding UTF8 en Get-Content en su lugar.
El script reutilizable find_duplicate_lines.bat incluido en esta guía reconoce UTF-8 con o sin BOM, admite UTF-16 y UTF-32 marcados con BOM y utiliza como alternativa la página de códigos ANSI de Windows cuando una secuencia de bytes sin BOM no es UTF-8 válida. Guarda tanto el informe de duplicados como la copia limpia en formato UTF-8 con BOM.
Get-Content, Group-Object, y Select-Object solo leen y analizan el archivo, salvo que añadas explícitamente un comando de escritura como Set-Content o Export-Csv.(Get-Content -LiteralPath ".\input.txt" -Encoding UTF8).Count. En un archivo muy grande, PowerShell sigue teniendo que leerlo y la operación puede tardar.find_duplicate_lines.bat. Crea automáticamente *_without_duplicates.txt y deja el archivo de origen sin cambios. La salida limpia conserva la primera aparición de cada línea exacta.Group-Object no distingue entre mayúsculas y minúsculas de forma predeterminada. Añade -CaseSensitive cuando deban compararse exactamente las letras mayúsculas y minúsculas.-Encoding UTF8 inmediatamente después de la ruta del archivo. Cambiar la consola con chcp 65001 por sí solo no corrige la forma en que Get-Content descodifica el archivo.find_duplicate_lines.bat lee el archivo seleccionado y crea *_duplicates.txt además de *_without_duplicates.txt. El archivo de texto original nunca se sobrescribe.Para comprobaciones repetidas, utiliza find_duplicate_lines.bat. Acepta un archivo mediante arrastrar y soltar, realiza una comparación exacta que distingue mayúsculas y minúsculas, crea un informe de duplicados ordenado alfabéticamente y escribe un segundo archivo UTF-8 sin apariciones duplicadas, conservando el orden original.
Utiliza PowerShell con Get-Content -Encoding UTF8 y Group-Object cuando solo necesites un informe interactivo o quieras personalizar las reglas de comparación. El comando de Windows sort.exe solo es adecuado para la inspección manual de archivos pequeños.