find_duplicate_lines.bat
Cria um relatório de duplicatas e um arquivo UTF-8 limpo, preservando a ordem das primeiras ocorrências.
Localizar e limparVerifique se um arquivo TXT contém linhas repetidas, crie uma cópia limpa sem duplicatas, preserve a ordem original, evite problemas de codificação UTF-8 ou use o PowerShell e o Prompt de Comando para verificações manuais.
O método reutilizável mais simples é o script BAT do Método 1. Arraste um arquivo TXT para ele para criar um relatório de duplicatas e uma cópia limpa sem linhas repetidas. O arquivo original não é alterado. Para uma verificação rápida somente no console, use o seguinte comando do PowerShell:
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Substitua input.txt pelo nome real do arquivo. Esse comando apenas informa as duplicatas; ele não cria um arquivo limpo. A opção -Encoding UTF8 é importante no Windows PowerShell 5.1, pois, sem ela, um arquivo UTF-8 sem marca de ordem de bytes pode ser decodificado como a página de códigos ANSI do Windows.
-CaseSensitive considera Server e server como linhas diferentes. Remova essa opção quando não for necessário diferenciar maiúsculas de minúsculas.
РіС..., o arquivo foi lido com a codificação incorreta. Mantenha -Encoding UTF8 para arquivos UTF-8. Use -Encoding Default para um arquivo ANSI antigo ou -Encoding Unicode para texto UTF-16 little-endian.
Cria um relatório de duplicatas e um arquivo UTF-8 limpo, preservando a ordem das primeiras ocorrências.
Localizar e limparMostra cada linha repetida e o número de ocorrências, mas pode ser lento em arquivos muito grandes.
Relatório rápidoColoca linhas iguais lado a lado, mas não informa nem remove duplicatas automaticamente.
Arquivos pequenosUma linha duplicada é aquela cujo valor de comparação aparece mais de uma vez no mesmo arquivo. No entanto, o resultado depende das regras de comparação escolhidas.
| Linhas | Comparação exata | Comparação sem diferenciar maiúsculas e minúsculas |
|---|---|---|
Windows e Windows |
Duplicada | Duplicada |
Windows e windows |
Diferentes | Duplicada |
example e example |
Diferentes por causa do espaço no final | Continuam diferentes, a menos que os espaços sejam removidos |
| Duas linhas vazias | Linha em branco duplicada | Linha em branco duplicada |
Para uma verificação rigorosa, use uma comparação que diferencie maiúsculas de minúsculas e não remova espaços. Em listas de nomes, URLs, domínios ou identificadores, pode ser melhor ignorar diferenças entre maiúsculas e minúsculas e espaços acidentais no início ou no fim da linha.
Para verificações recorrentes, use o seguinte script find_duplicate_lines.bat . Arraste um arquivo de texto para ele ou informe o caminho completo. O script cria dois arquivos UTF-8 na mesma pasta:
filename_duplicates.txt — um relatório com cada linha repetida e o número total de ocorrências.filename_without_duplicates.txt — uma cópia limpa na qual apenas a primeira ocorrência de cada linha é mantida.find_duplicate_lines.bat no campo de nome do arquivo.@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. Como alternativa, clique duas vezes no arquivo BAT e cole o caminho completo do arquivo de texto.filename_duplicates.txt para ver as linhas repetidas e a quantidade de ocorrências.filename_without_duplicates.txt para obter a lista limpa, sem as ocorrências duplicadas.| Arquivo | Comportamento da ordenação | Conteúdo |
|---|---|---|
filename_duplicates.txt |
Ordenado alfabeticamente pela linha duplicada | Uma entrada para cada valor duplicado, acompanhada da contagem total |
filename_without_duplicates.txt |
Não é ordenado; a ordem original é preservada | Somente a primeira ocorrência de cada linha exata |
| Arquivo TXT original | Não é ordenado nem modificado | Permanece inalterado |
Count Line
4 example.com
2 server-01
Windows e windows são tratadas como linhas diferentes.O PowerShell lê o arquivo como uma coleção de linhas. -Encoding UTF8 informa ao Windows PowerShell 5.1 que deve decodificar corretamente um arquivo UTF-8, inclusive arquivos UTF-8 sem marca de ordem de bytes. Group-Object agrupa as linhas iguais, e Where-Object mantém somente os grupos com mais de um item.
powershelle pressione Digite.input.txt pelo nome do seu arquivo.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
Esse resultado significa que example.com aparece quatro vezes, 192.168.1.10 aparece três vezes e Windows 11 aparece duas vezes.
Você pode executar a mesma verificação em qualquer pasta especificando o caminho completo:
Get-Content -LiteralPath "C:\Users\User\Desktop\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
-LiteralPath é preferível quando o nome do arquivo contém caracteres como colchetes, pois o PowerShell interpreta o caminho exatamente como foi escrito. Os exemplos usam -Encoding UTF8; substitua esse parâmetro pela codificação correta quando o arquivo de origem não estiver em UTF-8.
Use esta versão quando você só precisa saber se existe pelo menos uma linha 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."
}
O comando retorna apenas o primeiro grupo duplicado, embora o PowerShell ainda precise ler e agrupar o arquivo antes de gerar o resultado. Isso é útil em um script, uma tarefa agendada ou um fluxo de validação repetitivo.
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 salvar o relatório de duplicatas em vez de exibi-lo apenas no console, exporte os resultados agrupados para um arquivo 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
O arquivo de saída duplicate-report.csv pode ser aberto no Excel, no LibreOffice Calc, no Bloco de Notas ou em outro editor de texto.
Use o comando a seguir quando precisar de um arquivo TXT simples contendo uma cópia de cada linha que estava 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 enquanto o mesmo pipeline ainda estiver lendo esse arquivo.
Group-Object não diferencia maiúsculas de minúsculas por padrão. Remova -CaseSensitive para considerar PC, Pce pc como o mesmo 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
Isso faz com que example, examplee example sejam equivalentes. Isso não remove espaços dentro da linha.
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
O comando integrado do Windows sort.exe pode colocar linhas idênticas lado a lado. Isso facilita a identificação manual de duplicatas, mas o SORT não identifica, conta nem remove linhas repetidas automaticamente.
cmde pressione Digite.sort "input.txt" /o "sorted.txt"
Abra sorted.txt no Bloco de Notas. Os valores repetidos aparecerão lado a lado, permitindo uma verificação visual.
Para uma verificação automática pelo Prompt de Comando, chame o Windows PowerShell a partir do CMD. Este exemplo também especifica UTF-8 explicitamente para que caracteres cirílicos e acentuados não sejam decodificados como ANSI no 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"
O script BAT do Método 1 é mais eficiente que os exemplos curtos com Group-Object , pois ele não lê o arquivo inteiro para um array nem ordena alfabeticamente cada linha de origem. Ele faz uma leitura sequencial, grava as primeiras ocorrências diretamente no arquivo limpo e mantém na memória apenas as chaves únicas e seus contadores.
Os comandos diretos do PowerShell continuam sendo práticos, mas Group-Object pode ser visivelmente mais lento e consumir muita memória RAM em arquivos grandes.
Para um arquivo grande, tome estas precauções:
Group-Object.Se o PowerShell exibir texto cirílico, acentuado ou em outros idiomas como sequências do tipo РіС..., o arquivo de origem provavelmente está sendo decodificado com a codificação de caracteres errada. O texto em si pode continuar intacto; o problema está na forma como Get-Content interpreta os bytes do arquivo.
-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
Isso funciona com texto UTF-8 com ou sem marca de ordem de bytes no Windows PowerShell 5.1. Em versões mais recentes do PowerShell, UTF-8 costuma ser o padrão para várias operações de texto, mas especificá-lo explicitamente elimina qualquer ambiguidade.
| Codificação do arquivo de origem | Parâmetro do Get-Content | Quando usar |
|---|---|---|
| UTF-8 | -Encoding UTF8 |
Recomendado para arquivos TXT modernos, inclusive UTF-8 sem BOM. |
| Página de códigos ANSI do Windows | -Encoding Default |
Use em arquivos antigos salvos na página de códigos atual do sistema Windows. |
| UTF-16 little-endian | -Encoding Unicode |
Use em arquivos UTF-16 LE, geralmente identificados por um FF FE BOM. |
| UTF-16 big-endian | -Encoding BigEndianUnicode |
Use em arquivos UTF-16 BE, geralmente identificados por um 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 altera a página de códigos do console, mas não informa ao Get-Content como decodificar o arquivo de origem. Especifique -Encoding UTF8 em Get-Content em vez disso.
O script reutilizável find_duplicate_lines.bat incluído neste guia reconhece UTF-8 com ou sem BOM, aceita UTF-16 e UTF-32 marcados com BOM e usa a página de códigos ANSI do Windows quando uma sequência de bytes sem BOM não é um UTF-8 válido. Ele grava tanto o relatório de duplicatas quanto a cópia limpa em UTF-8 com BOM.
Get-Content, Group-Objecte Select-Object apenas leem e analisam o arquivo, a menos que você adicione explicitamente um comando de gravação, como Set-Content ou Export-Csv.(Get-Content -LiteralPath ".\input.txt" -Encoding UTF8).Count. Em um arquivo muito grande, o PowerShell ainda precisa ler todo o conteúdo, o que pode levar algum tempo.find_duplicate_lines.bat. Ele cria automaticamente *_without_duplicates.txt e mantém o arquivo de origem inalterado. O arquivo limpo conserva a primeira ocorrência de cada linha exata.Group-Object não diferencia maiúsculas de minúsculas por padrão. Adicione -CaseSensitive quando letras maiúsculas e minúsculas precisarem ser comparadas de forma exata.-Encoding UTF8 imediatamente após o caminho do arquivo. Alterar o console com chcp 65001 por si só não corrige a forma como Get-Content decodifica o arquivo.find_duplicate_lines.bat lê o arquivo selecionado e cria *_duplicates.txt e também *_without_duplicates.txt. O arquivo de texto original nunca é sobrescrito.Para verificações recorrentes, use find_duplicate_lines.bat. Ele aceita um arquivo por arrastar e soltar, realiza uma comparação exata que diferencia maiúsculas de minúsculas, cria um relatório de duplicatas ordenado alfabeticamente e grava um segundo arquivo UTF-8 sem ocorrências duplicadas, preservando a ordem original.
Use o PowerShell com Get-Content -Encoding UTF8 e Group-Object quando precisar apenas de um relatório interativo ou quiser personalizar as regras de comparação. O comando do Windows sort.exe é adequado somente para a inspeção manual de arquivos pequenos.