web-dev-qa-db-fra.com

Lot pour supprimer les lignes en double du fichier texte

Est-il possible de supprimer les lignes en double d'un fichier texte? Si oui comment? 

10
Rocshy

Bien sûr, mais comme la plupart des traitements de fichiers texte avec batch, ce n’est pas beau et n’est pas particulièrement rapide.

Cette solution ignore la casse lors de la recherche de doublons et trie les lignes. Le nom du fichier est transmis en tant que premier et unique argument du script de traitement par lots.

@echo off
setlocal disableDelayedExpansion
set "file=%~1"
set "sorted=%file%.sorted"
set "deduped=%file%.deduped"
::Define a variable containing a linefeed character
set LF=^


::The 2 blank lines above are critical, do not remove
sort "%file%" >"%sorted%"
>"%deduped%" (
  set "prev="
  for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%sorted%") do (
    set "ln=%%A"
    setlocal enableDelayedExpansion
    if /i "!ln!" neq "!prev!" (
      endlocal
      (echo %%A)
      set "prev=%%A"
    ) else endlocal
  )
)
>nul move /y "%deduped%" "%file%"
del "%sorted%"

Cette solution est sensible à la casse et laisse les lignes dans l'ordre d'origine (sauf pour les doublons bien sûr). Encore une fois, le nom du fichier est transmis en tant que premier et unique argument.

@echo off
setlocal disableDelayedExpansion
set "file=%~1"
set "line=%file%.line"
set "deduped=%file%.deduped"
::Define a variable containing a linefeed character
set LF=^


::The 2 blank lines above are critical, do not remove
>"%deduped%" (
  for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file%") do (
    set "ln=%%A"
    setlocal enableDelayedExpansion
    >"%line%" (echo !ln:\=\\!)
    >nul findstr /xlg:"%line%" "%deduped%" || (echo !ln!)
    endlocal
  )
)
>nul move /y "%deduped%" "%file%"
2>nul del "%line%"


EDIT

Les deux solutions au-dessus des lignes vides. Je ne pensais pas que les lignes vierges méritaient d'être préservées lorsqu'on parlait de valeurs distinctes.

J'ai modifié les deux solutions pour désactiver l'option "EOL" de FOR/F afin que toutes les lignes non vides soient préservées, quel que soit le premier caractère. Le code modifié définit l'option EOL sur un caractère de saut de ligne.


Nouvelle solution 2016-04-13: JSORT.BAT

Vous pouvez utiliser mon Utilitaire hybride JScript/batch JSORT.BAT pour trier et supprimer efficacement les doublons avec un simple trait (plus un MOVE pour remplacer le fichier d'origine par le résultat final). JSORT est un script pur qui s'exécute de manière native sur toute machine Windows à partir de XP.

@jsort file.txt /u >file.txt.new
@move /y file.txt.new file.txt >nul
13
dbenham
9
PA.
set "file=%CD%\%1"
sort "%file%">"%file%.sorted"
del /q "%file%"
FOR /F "tokens=*" %%A IN (%file%.sorted) DO (
SETLOCAL EnableDelayedExpansion
if not [%%A]==[!LN!] (
set "ln=%%A"
echo %%A>>"%file%"
)
)
ENDLOCAL
del /q "%file%.sorted"

Cela devrait fonctionner exactement de la même manière. Cet exemple de Dbenham semblait beaucoup trop hardcore pour moi, alors j'ai testé ma propre solution. utilisation ex .: filedup.cmd nomfichier.ext

3
genetix

Le fichier batch ci-dessous fait ce que vous voulez:

@echo off
setlocal EnableDelayedExpansion
set "prevLine="
for /F "delims=" %%a in (theFile.txt) do (
   if "%%a" neq "!prevLine!" (
      echo %%a
      set "prevLine=%%a"
   )
)

Si vous avez besoin d'une méthode plus efficace, essayez ce script hybride Batch-JScript développé en tant que filter , c'est-à-dire similaire au programme Unix uniq. Enregistrez-le avec l'extension .bat, comme uniq.bat:

@if (@CodeSection == @Batch) @then

@CScript //nologo //E:JScript "%~F0" & goto :EOF

@end

var line, prevLine = "";
while ( ! WScript.Stdin.AtEndOfStream ) {
   line = WScript.Stdin.ReadLine();
   if ( line != prevLine ) {
      WScript.Stdout.WriteLine(line);
      prevLine = line;
   }
}

Les deux programmes ont été copiés à partir de cet article .

2
Aacini

Pure batch - 3 lignes efficaces.

@ECHO OFF
SETLOCAL
:: remove variables starting $
FOR  /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="

FOR /f "delims=" %%a IN (q34223624.txt) DO SET $%%a=Y
(FOR  /F "delims=$=" %%a In ('set $ 2^>Nul') DO ECHO %%a)>u:\resultfile.txt

GOTO :EOF

Fonctionne avec bonheur si les données ne contiennent pas de caractères pour lesquels le lot a une sensibilité.

"q34223624.txt" car la question 34223624 contenait ces données

1.1.1.1
1.1.1.1
1.1.1.1
1.2.1.2
1.2.1.2
1.2.1.2
1.3.1.3
1.3.1.3
1.3.1.3

sur lequel cela fonctionne parfaitement.

2
Magoo

J'ai utilisé un faux "tableau" pour accomplir cela

@echo off
:: filter out all duplicate ip addresses
REM you file would take place of %1
set file=%1%
if [%1]==[] goto :EOF
setlocal EnableDelayedExpansion
set size=0
set cond=false
set max=0
for /F %%a IN ('type %file%') do (   
      if [!size!]==[0] (
          set cond=true
          set /a size="size+1"
          set arr[!size!]=%%a

      ) ELSE (
                 call :inner
                 if [!cond!]==[true] (
                     set /a size="size+1" 
                     set arr[!size!]=%%a&& ECHO > NUL                      
                 ) 
      )
)
break> %file%
:: destroys old output
for /L %%b in (1,1,!size!) do echo !arr[%%b]!>> %file%
endlocal
goto :eof
:inner
for /L %%b in (1,1,!size!) do (  
          if "%%a" neq "!arr[%%b]!" (set cond=true) ELSE (set cond=false&&goto :break)                                
)
:break

l'utilisation de l'étiquette pour la boucle interne est quelque chose de spécifique à cmd.exe et constitue le seul moyen de réussir à imbriquer des boucles les unes dans les autres. En gros, cela compare chaque nouvelle valeur transmise en tant que délimiteur. S'il n'y a pas de correspondance, le programme ajoute la valeur en mémoire. Quand cela sera fait, le contenu du fichier cible sera détruit et remplacé par les chaînes uniques.

1
user4301289

J'ai rencontré ce problème et je devais le résoudre moi-même, car l'utilisation était particulière pour mon besoin. Je devais trouver des URL en double et l'ordre des lignes était pertinent, il fallait donc le conserver. Les lignes de texte ne doivent pas contenir de guillemets, ne doivent pas être trop longues et le tri ne peut pas être utilisé.

Ainsi j'ai fait ceci:

setlocal enabledelayedexpansion
type nul>unique.txt
for /F "tokens=*" %%i in (list.txt) do (
    find "%%i" unique.txt 1>nul
    if !errorlevel! NEQ 0 (
        echo %%i>>unique.txt
    )
)

Auxiliaire: si le texte contient des guillemets doubles, alors FIND doit utiliser une variable de jeu filtrée, comme décrit dans cet article: Escape les guillemets doubles dans le paramètre

Donc au lieu de:

find "%%i" unique.txt 1>nul

ce serait plus comme:

set test=%%i
set test=!test:"=""!
find "!test!" unique.txt 1>nul

Ainsi, find ressemblera à find "" "what" "" file et %% i sera inchangé.

0
JasonXA