find_duplicate_lines.bat
Crée un rapport des doublons et un fichier UTF-8 nettoyé tout en conservant l’ordre des premières occurrences.
Rechercher et nettoyerVérifiez si un fichier TXT contient des lignes répétées, créez une copie nettoyée sans doublons, conservez l’ordre d’origine, évitez les problèmes d’encodage UTF-8 ou utilisez PowerShell et l’Invite de commandes pour effectuer des vérifications manuelles.
La méthode réutilisable la plus simple est le script BAT de la méthode 1. Faites glisser un fichier TXT dessus pour créer à la fois un rapport des doublons et une copie nettoyée sans lignes répétées. Le fichier d’origine n’est pas modifié. Pour une vérification rapide uniquement dans la console, utilisez la commande PowerShell suivante :
Get-Content -LiteralPath ".\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Sort-Object Count -Descending |
Select-Object Count, Name
Remplacez input.txt par le nom réel du fichier. Cette commande signale uniquement les doublons ; elle ne crée pas de fichier nettoyé. L’option -Encoding UTF8 est importante dans Windows PowerShell 5.1, car un fichier UTF-8 sans marque d’ordre des octets risque sinon d’être décodé selon la page de codes ANSI de Windows.
-CaseSensitive considère Server et server comme des lignes différentes. Supprimez cette option lorsque la casse doit être ignorée.
РіС..., le fichier a été lu avec un encodage incorrect. Conservez -Encoding UTF8 pour les fichiers UTF-8. Utilisez -Encoding Default pour un ancien fichier ANSI ou -Encoding Unicode pour un texte UTF-16 little-endian.
Crée un rapport des doublons et un fichier UTF-8 nettoyé tout en conservant l’ordre des premières occurrences.
Rechercher et nettoyerAffiche chaque ligne répétée et son nombre d’occurrences, mais peut être lent sur les fichiers très volumineux.
Rapport rapidePlace les lignes identiques les unes à côté des autres, mais ne signale ni ne supprime automatiquement les doublons.
Petits fichiersUne ligne en double est une ligne dont la valeur de comparaison apparaît plusieurs fois dans le même fichier. Le résultat dépend toutefois des règles de comparaison choisies.
| Lignes | Comparaison exacte | Comparaison sans distinction de casse |
|---|---|---|
Windows et Windows |
En double | En double |
Windows et windows |
Différentes | En double |
example et example |
Différentes à cause de l’espace final | Toujours différentes tant que les espaces ne sont pas supprimés |
| Deux lignes vides | Ligne vide en double | Ligne vide en double |
Pour une vérification stricte, utilisez une comparaison sensible à la casse et ne supprimez pas les espaces. Pour des listes de noms, d’URL, de domaines ou d’identifiants, il peut être préférable d’ignorer la casse ainsi que les espaces accidentels au début ou à la fin des lignes.
Pour des vérifications régulières, utilisez le script find_duplicate_lines.bat suivant. Faites glisser un fichier texte dessus ou saisissez son chemin complet. Le script crée deux fichiers UTF-8 dans le même dossier :
filename_duplicates.txt — un rapport contenant chaque ligne répétée et son nombre total d’occurrences.filename_without_duplicates.txt — une copie nettoyée dans laquelle seule la première occurrence de chaque ligne est conservée.find_duplicate_lines.bat dans le champ du nom de fichier.@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. Vous pouvez également double-cliquer sur le fichier BAT et coller le chemin complet du fichier texte.filename_duplicates.txt pour voir les lignes répétées et leur nombre d’occurrences.filename_without_duplicates.txt pour obtenir la liste nettoyée dont les occurrences en double ont été supprimées.| Fichier | Comportement du tri | Contenu |
|---|---|---|
filename_duplicates.txt |
Trié par ordre alphabétique selon la ligne en double | Une entrée par valeur répétée, accompagnée de son nombre total |
filename_without_duplicates.txt |
Non trié ; l’ordre d’origine est conservé | Uniquement la première occurrence de chaque ligne exacte |
| Fichier TXT d’origine | Ni trié ni modifié | Reste inchangé |
Count Line
4 example.com
2 server-01
Windows et windows sont considérées comme des lignes différentes.PowerShell lit le fichier comme une collection de lignes. -Encoding UTF8 indique à Windows PowerShell 5.1 de décoder correctement un fichier UTF-8, y compris lorsqu’il ne contient pas de marque d’ordre des octets. Group-Object regroupe les lignes identiques, tandis que Where-Object ne conserve que les groupes contenant plusieurs éléments.
powershell, puis appuyez sur Saisissez.input.txt par le nom de votre fichier.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
Ce résultat signifie que example.com apparaît quatre fois, 192.168.1.10 apparaît trois fois et que Windows 11 apparaît deux fois.
Vous pouvez effectuer la même vérification depuis n’importe quel dossier en indiquant le chemin complet :
Get-Content -LiteralPath "C:\Users\User\Desktop\input.txt" -Encoding UTF8 |
Group-Object -CaseSensitive |
Where-Object Count -gt 1 |
Select-Object Count, Name
-LiteralPath est préférable lorsque le nom du fichier contient des caractères tels que des crochets, car PowerShell traite alors le chemin exactement comme il est écrit. Les exemples utilisent -Encoding UTF8; remplacez-le par le paramètre d’encodage approprié lorsque le fichier source n’est pas en UTF-8.
Utilisez cette version lorsque vous souhaitez seulement savoir si au moins une ligne répétée existe :
$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."
}
La commande renvoie uniquement le premier groupe en double, même si PowerShell doit tout de même lire et regrouper le fichier avant de produire le résultat. Elle est utile dans un script, une tâche planifiée ou une procédure de validation répétable.
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" }
Pour enregistrer le rapport des doublons au lieu de l’afficher uniquement dans la console, exportez les résultats regroupés vers un fichier 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
Le fichier de sortie duplicate-report.csv peut être ouvert dans Excel, LibreOffice Calc, le Bloc-notes ou un autre éditeur de texte.
Utilisez la commande suivante lorsque vous avez besoin d’un fichier TXT simple contenant une copie de chaque ligne qui était répétée :
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 tant que le même pipeline lit encore ce fichier.
Group-Object ne distingue pas la casse par défaut. Supprimez -CaseSensitive pour considérer PC, Pcet pc comme une même valeur :
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
Cela rend example, exampleet example équivalents. Les espaces à l’intérieur d’une ligne ne sont pas supprimés.
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
La commande Windows intégrée sort.exe peut placer les lignes identiques les unes à côté des autres. Les doublons sont ainsi plus faciles à repérer manuellement, mais SORT n’identifie, ne compte et ne supprime pas automatiquement les lignes répétées.
cmd, puis appuyez sur Saisissez.sort "input.txt" /o "sorted.txt"
Ouvrez sorted.txt dans le Bloc-notes. Les valeurs répétées apparaîtront les unes à côté des autres, ce qui permet une vérification visuelle.
Pour effectuer une vérification automatique depuis l’Invite de commandes, appelez Windows PowerShell depuis CMD. Cet exemple indique également explicitement l’UTF-8 afin que les caractères cyrilliques et accentués ne soient pas décodés comme de l’ANSI dans 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"
Le script BAT de la méthode 1 est plus efficace que les exemples courts utilisant Group-Object , car il ne charge pas tout le fichier dans un tableau et ne trie pas chaque ligne source par ordre alphabétique. Il effectue une lecture séquentielle, écrit directement les premières occurrences dans le fichier nettoyé et conserve uniquement les clés uniques ainsi que leurs compteurs en mémoire.
Les commandes PowerShell directes restent pratiques, mais Group-Object peut être sensiblement plus lent et consommer beaucoup de mémoire vive sur un fichier volumineux.
Pour un fichier volumineux, prenez les précautions suivantes :
Group-Object.Si PowerShell affiche du texte cyrillique, accentué ou dans une autre langue sous forme de séquences telles que РіС..., le fichier source est généralement décodé avec un encodage de caractères incorrect. Le texte lui-même peut être intact ; le problème vient de la manière dont Get-Content interprète les octets du fichier.
-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
Cela fonctionne avec les textes UTF-8 avec ou sans marque d’ordre des octets dans Windows PowerShell 5.1. Dans les versions plus récentes de PowerShell, l’UTF-8 est généralement utilisé par défaut pour de nombreuses opérations de texte, mais l’indiquer explicitement évite toute ambiguïté.
| Encodage du fichier source | Paramètre de Get-Content | Quand l’utiliser |
|---|---|---|
| UTF-8 | -Encoding UTF8 |
Recommandé pour les fichiers TXT modernes, y compris l’UTF-8 sans BOM. |
| Page de codes ANSI de Windows | -Encoding Default |
À utiliser pour les anciens fichiers enregistrés avec la page de codes système actuelle de Windows. |
| UTF-16 little-endian | -Encoding Unicode |
À utiliser pour les fichiers UTF-16 LE, souvent identifiés par un FF FE BOM. |
| UTF-16 big-endian | -Encoding BigEndianUnicode |
À utiliser pour les fichiers UTF-16 BE, souvent identifiés par un 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 modifie la page de codes de la console, mais n’indique pas à Get-Content comment décoder le fichier source. Indiquez -Encoding UTF8 sur Get-Content à la place.
Le script réutilisable find_duplicate_lines.bat inclus dans ce guide reconnaît l’UTF-8 avec ou sans BOM, prend en charge l’UTF-16 et l’UTF-32 munis d’un BOM et utilise la page de codes ANSI de Windows lorsqu’une séquence d’octets sans BOM n’est pas un UTF-8 valide. Il enregistre le rapport des doublons et la copie nettoyée en UTF-8 avec BOM.
Get-Content, Group-Objectet Select-Object se contentent de lire et d’analyser le fichier, sauf si vous ajoutez explicitement une commande d’écriture telle que Set-Content ou Export-Csv.(Get-Content -LiteralPath ".\input.txt" -Encoding UTF8).Count. Pour un fichier très volumineux, PowerShell doit malgré tout lire tout le fichier, ce qui peut prendre du temps.find_duplicate_lines.bat. Il crée automatiquement *_without_duplicates.txt et laisse le fichier source inchangé. Le fichier nettoyé conserve la première occurrence de chaque ligne exacte.Group-Object ne distingue pas la casse par défaut. Ajoutez -CaseSensitive lorsque les majuscules et les minuscules doivent être comparées exactement.-Encoding UTF8 immédiatement après le chemin du fichier. Modifier la console avec chcp 65001 seul ne corrige pas la manière dont Get-Content décode le fichier.find_duplicate_lines.bat lit le fichier sélectionné et crée *_duplicates.txt ainsi que *_without_duplicates.txt. Le fichier texte d’origine n’est jamais remplacé.Pour des vérifications régulières, utilisez find_duplicate_lines.bat. Il accepte un fichier par glisser-déposer, effectue une comparaison exacte sensible à la casse, crée un rapport des doublons trié par ordre alphabétique et écrit un second fichier UTF-8 sans occurrences répétées tout en conservant l’ordre d’origine.
Utilisez PowerShell avec Get-Content -Encoding UTF8 et Group-Object lorsque vous avez seulement besoin d’un rapport interactif ou souhaitez personnaliser les règles de comparaison. La commande Windows sort.exe convient uniquement à l’inspection manuelle de petits fichiers.