2012-07-27 22 views

risposta

9

Certo, ma come la maggior parte dell'elaborazione di file di testo con batch, non è carina e non è particolarmente veloce.

Questa soluzione ignora il caso quando si cercano i duplicati e si ordina le righe. Il nome del file viene passato come primo e unico argomento dello script batch.

@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%" 

Questa soluzione è caso sensibile e lascia le linee nell'ordine originale (eccetto duplicati naturalmente). Ancora una volta il nome del file viene passato come primo e unico argomento.

@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

Entrambe le soluzioni sopra striscia righe vuote. Non pensavo che valesse la pena preservare le righe vuote quando si parla di valori distinti.

Ho modificato entrambe le soluzioni per disabilitare l'opzione "EOL" FOR/F in modo che tutte le righe non vuote siano conservate, indipendentemente dal 1 ° carattere. Il codice modificato imposta l'opzione EOL su un carattere di avanzamento riga.


Nuova soluzione 2016/04/13: JSORT.BAT

È possibile utilizzare il mio JSORT.BAT hybrid JScript/batch utility in modo efficiente ordinare e rimuovere le linee duplicate con un semplice uno di linea (più una mossa per sovrascrivere il file originale con il risultato finale). JSORT è puro script che viene eseguito in modo nativo su qualsiasi macchina Windows da XP in poi.

@jsort file.txt /u >file.txt.new 
@move /y file.txt.new file.txt >nul 
+0

Ran nella stringa di ricerca di finstr è troppo lungo. –

+1

@Dreadedsemicolon - Sì, non pensavo di menzionare che la seconda opzione fallisce se alcune linee superano la lunghezza 511 (127 su XP) a causa dei limiti FINDSTR. – dbenham

3
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" 

Questo dovrebbe funzionare esattamente lo stesso. Quell'esempio di dbenham mi è sembrato troppo difficile, quindi ho provato la mia soluzione. utilizzo ex .: filedup.cmd nomefile.ext

+0

Solo una FYI: la prima istruzione 'set' non funzionerà sempre. Ho visto il% CD% fallire e/o essere sovrascritto molte volte! Dovresti usare questo invece "set" file =% ~ dpnx1 "'. Le lettere in% 1 sono definite come: d = unità, p = percorso, n = nome file (senza estensione), x = estensione. Funziona per il primo argomento anche quando si passa solo il nome file (senza percorso). – wasatchwizard

0

Si è imbattuto in questo problema e ho dovuto risolverlo da solo perché l'utilizzo era particulare per il mio bisogno. Avevo bisogno di trovare gli URL duplicati e l'ordine delle linee era rilevante, quindi doveva essere preservato. Le righe di testo non dovrebbero contenere virgolette doppie, non dovrebbero essere molto lunghe e l'ordinamento non può essere usato.

Così ho fatto questo:

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 
    ) 
) 

ausiliario: se il testo non contiene virgolette doppie poi la TROVA bisogno di usare una variabile insieme filtrato come descritto in questo post: Escape double quotes in parameter

Così, invece di:

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

sarebbe più simile a:

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

Quindi, la ricerca sembrerà trovare "" "cosa" "" file e %% i rimarranno invariati.

1

ho usato un "matrice" falso per raggiungere questo

@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'uso dell'etichetta per il ciclo interno è qualcosa di specifico per cmd.exe e è l'unico modo sono stato nidificazione successo per cicli dentro l'altro. Fondamentalmente questo confronta ogni nuovo valore che viene passato come delimitatore e se non c'è corrispondenza, il programma aggiungerà il valore in memoria. Quando si è fatto distruggerà i contenuti file di destinazione e sostituirli con le stringhe univoche

2

Il file batch di seguito fare quello che vuoi:

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

Se avete bisogno di un metodo più efficiente, provate questo per lotti Script ibrido JScript sviluppato come filtro , ovvero simile al programma Unix uniq. Salvarlo con estensione .bat, come 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; 
    } 
} 

Entrambi i programmi sono stati copiati da this post.

2

lotto puro: 3 linee effettive.

@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 

Funziona felicemente se i dati non contengono caratteri a cui il lotto ha una sensibilità.

"q34223624.txt", perché domanda 34.223.624 conteneva questi dati

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 

su cui funziona perfettamente.

Problemi correlati