2012-07-27 53 views

Respuesta

9

Claro, pero al igual que la mayoría del procesamiento de archivos de texto con lotes, no es bonito, y no es particularmente rápido.

Esta solución ignora el caso al buscar duplicados y ordena las líneas. El nombre del archivo se pasa como el primer y único argumento al script por lotes.

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

Esta solución distingue entre mayúsculas y minúsculas y deja las líneas en el orden original (excepto por duplicados, por supuesto). De nuevo, el nombre del archivo se pasa como el primer y único argumento.

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


EDITAR

Ambas soluciones anteriores líneas en blanco tira. No pensé que valía la pena preservar las líneas en blanco cuando hablaba de valores distintos.

He modificado ambas soluciones para desactivar la opción FOR/F "EOL" para que se conserven todas las líneas no en blanco, independientemente de cuál sea el primer carácter. El código modificado establece la opción EOL en un carácter de avance de línea.


Nueva solución 13/04/2016: JSORT.BAT

Usted puede usar mi JSORT.BAT hybrid JScript/batch utility de manera eficiente ordenar y eliminar las líneas duplicadas con un simple forro (además de un movimiento para sobrescribir el archivo original con el resultado final). JSORT es una secuencia de comandos pura que se ejecuta de forma nativa en cualquier máquina con Windows desde XP en adelante.

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

Ran en la cadena de búsqueda finstr es demasiado larga. –

+1

@Dreadedsemicolon - Sí, no pensé mencionar que la segunda opción falla si las líneas superan la longitud 511 (127 en XP) debido a los límites de 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" 

Esto debería funcionar exactamente igual. Ese ejemplo de dbenham me pareció demasiado duro, así que probé mi propia solución. use ex .: filedup.cmd filename.ext

+0

Solo un FYI: la primera declaración 'set' no siempre funcionará. ¡He visto que% CD% falla y/o se sobrescribe muchas veces! Debería usar esto en su lugar 'set 'file =% ~ dpnx1' '. Las letras en% 1 se definen como: d = unidad, p = ruta, n = nombre de archivo (sin extensión), x = extensión. Esto funciona para el primer argumento incluso cuando solo ingresas el nombre del archivo (sin ruta). – wasatchwizard

0

Me encontré con este problema y tuve que resolverlo yo mismo porque el uso era particulado para mi necesidad. Necesitaba encontrar direcciones URL duplicadas y el orden de las líneas era relevante, por lo que necesitaba ser preservado. Las líneas de texto no deben contener comillas dobles, no deben ser muy largas y la clasificación no se puede usar.

Así lo hice:

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

auxiliar: si el texto contiene comillas dobles entonces el FIND tiene que utilizar una variable conjunto filtrado como se describe en este post: Escape double quotes in parameter

Así que en lugar de:

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

sería más como:

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

Por lo tanto, buscar se verá como encontrar "" "qué" "archivo y %% no cambiaré.

1

he utilizado una "matriz" falsa para lograr esto

@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 

el uso de la etiqueta para el bucle interno es algo específico de cmd.exe y es la única manera que he sido anidación exitosa para los bucles dentro de cada uno. Básicamente, esto compara cada nuevo valor que se pasa como un delimitador y si no hay coincidencia, el programa agregará el valor en la memoria. Una vez hecho esto se va a destruir el contenido archivos de destino y sustituirlas por las cadenas únicas

2

el archivo por lotes a continuación hacer lo que quiera:

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

Si necesita un método más eficiente, prueba esto por lotes Script híbrido de JScript que se desarrolla como un filtro , es decir, similar al programa Unix uniq. Guardarlo con la extensión .bat, como 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; 
    } 
} 

Ambos programas fueron copiados de this post.

2

Lote puro: 3 líneas efectivas.

@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 

Funciona correctamente si los datos no contienen caracteres a los que el lote tiene una sensibilidad.

"q34223624.txt" porque la pregunta 34223624 contenía estos datos

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 

en la que funciona perfectamente.

Cuestiones relacionadas