Realizar un batch para ver líneas duplicadas

Ten un fichero ubicaciones.txt

c:\datos

d:\datos

e:\datos

f:\datos

d:\datos

f:\datos

d:\datos

g:\imagenes

Quisiera saber si alguna ubicación esta mentida en la lista más de una vez y crear un fichro log con las ubicaciones duplicadas

pro ejemplo que el resultado del log fuera

final.log

d:\datos

f:\datos

d:\datos

1 respuesta

Respuesta
1

Prueba con esto vilda/Anónimo (¿o me he pasado de listo?):

@echo off
Setlocal EnableDelayedExpansion
del /q final.log
set /a fila=0
for /f "tokens=1*" %%a in (ubicaciones.txt) do (set /a fila+=1&call :comprob %%a !fila!)
goto :eof
:comprob
for /f "skip=%2 tokens=1*" %%x in (ubicaciones.txt) do (if "%%x"=="%1" echo %%x >>final.log&goto :eof)

Tengo alguna duda de que funcione completamente bien, de modo que sería bueno probarlo un poco a fondo. Ya me dirás.

No se que pasa pero si tenemos en la lista de ubicaciones unas carpetas que contiene un espacio, del estilo a
C:\Mis documentos
C:\Mis imágenes
El resultado que obtenemos es que nos dá como duplicada la carteps C:\Mis
Yo tenia entendido que tokens=1* esto es para leer toda la linea entera aunque tenga espacios u otros caracteres, pero parece ser no funciona así.
A por cierto en la lista de ubicaciones, a veces puede existir seguido de // una descripción que quiero que ignore en la comparación, osea que para la comparación deberíamos de tomar siempre toda la lianea completa o de existir //, so qie quieres simplemente / todo lo que esté antes de esta marca Ejemplo
C:\Mis documentos //Documentos importantes
d:\datos //Datos de la escuela
C:\Mis documentos
El resultado sería que tiene que dar por duplicada la carpeta C:\Misdocumentos, aunque la descripción no coincida o ni tan siquiera exista
Lo esoy intentando con
@echo off
Setlocal EnableDelayedExpansion
del /q final.log
set /a fila=0
for /f "tokens=1 delims=/" %%a in (ubicaciones.txt) do (set /a fila+=1&call :comprob %%a !fila!)
goto :eof
:comprob
for /f "skip=%2 tokens=1 delims=/" %%x in (ubicaciones.txt) do (if "%%x"=="%1" echo %%x >>final.log&goto :eof)
Parece que funciona bien, excepto si existe una carpeta de las que contiene algún espacio, entonces me dice

No se esperaba documentos tokens=1 delims=/ en este momento

Me imagino que tu si que ves claro por que está sucediendo esto

Gracias por atenderme

Vale. No hay problema, creo. Pensé que no iba a haber espacios en los nombres.

Lo que dices del tokens=1* es correcto. Pero al usar %%a como parámetro en la llamada a subrutina ":comprob" los espacios se consideran delimitadores de parámetros de modo que el primer parámetro sería "c:\Mis" y el segundo "documentos" lo cual estropea el funcionamiento. Y para no tener en cuenta los comentarios es correcta tu propuesta. De modo que el bat debería quedar así:

@echo off
Setlocal EnableDelayedExpansion
del /q final.log
set /a nfila=0
for /f "tokens=1 delims=/" %%a in (ubicaciones.txt) do (set /a nfila+=1&call :comprob "%%a" !nfila!)
goto :eof
:comprob
for /f "skip=%2 tokens=1 delims=/" %%x in (ubicaciones.txt) do (if "%%x"==%1 echo %%x >>final.log&goto :eof)

Hay un pequeño problema con los "comentarios". Si existen se incorporará un espacio final a la variable %%a (el que separa la carpeta del inicio de los comentarios). Esto haría que, por ejemplo, "c:\pepito" no se considerase igual que "c:\pepito //carpeta de pepito". Esto obliga a distinguir de alguna manera las líneas sin comentarios de las que los tienen. He optado por añadir un espacio cuando no hay comentario.

Quedaría así:

@echo off
Setlocal EnableDelayedExpansion
del /q final.log
set /a nfila=0
for /f "tokens=1,2* delims=/" %%a in (ubicaciones.txt) do (
set /a nfila+=1
set dir=%%a
if not "%%b"=="" set dir=!dir! 
call :comprob "!dir!" !nfila!
)
goto :eof
:comprob
for /f "skip=%2 tokens=1,2* delims=/" %%x in (ubicaciones.txt) do (if "%%x"==%1 echo %%x >>final.log&goto :eof)

Esta solución tiene el problema de que solo vale si entre los comentarios y el final del directorio/carpeta hay un solo espacio. Voy a pensar en una solución más general que sea capaz de eliminar todos los espacios menos los que formen parte del nombre  de la carpeta/directorio. 

Se me olvidó comentar que en la instrucción:

if not "%%b"=="" set dir=!dir! 

 es fundamental el espacio final. Es decir que después de !dir! debe haber un espacio.

Olvida lo anterior. No vale. Voy a darle una vuelta más al tema de los espacios.

Si que tiene razón, he probado la solución anterior a la de los espacios y aparentemente funciona todo perfecto, salvo lo de los espacios al final, y es que claro, una carpeta la pueden escribir:
C:\Mis documentos

C:\Mis documentos //Documentos importantes

C:\Mis documentos                                                                           //Documentos importantes

Y claro que alpasarle nuestra solución nos diría que no existe ninguna coincidencia

Pero no se como ni por que pasa he visto otro problema, y es que si en la lista de ubicaciones incluimos, por la mitad aproximadamente, una líneas completamente en blanco, el resultado se descontrola del todo.

No se como resolverlo y tampoco se porque ocurre

Creo que ya he conseguido resolver el problema del número variable de espacios. Seguramente habrá formas más sencillas de conseguirlo pero esta es la que he encontrado (y me ha dado un poco de guerra, no creas):

@echo off
Setlocal EnableDelayedExpansion
del /q final.log
set fila=
set /a nfila=0
for /f "tokens=1 delims=/" %%a in (ubicaciones.txt) do (
set /a nfila+=1
if not "%%a"=="" call :limpiaespacios "%%a"&call :comprob "!fila!" !nfila!
)
goto :eof
:comprob
for /f "skip=%2 tokens=1 delims=/" %%x in (ubicaciones.txt) do (
if not "%%x"=="" (call :limpiaespacios "%%x"
if "!fila!"==%1 echo !fila! >>final.log&goto :eof
)
)
goto :eof
:limpiaespacios
set ent=%~1
:bucle
if "%ent:~-1,1%"==" " set ent=%ent:~0,-1%&goto :bucle
set fila=%ent%
goto :eof

Como puedes ver se ha complicado considerablemente.

En cuanto a la presencia de líneas en blanco sé por experiencia que suponen una tortura para los bat. Tengo que rebuscar en lo que he hecho en el pasado porque creo que había encontrado una forma, bastante retorcida, eso sí, de salvar ese "escollo". Ya te contaré. De momento mira a ver si el bat anterior resuelve todo lo demás.

Por cierto, si quieres incluir algo en una ventanita como la que utilizo, solo debes usar la herramienta snippet ("Insertar código fuente", icono <> de la barra de herramientas de la página). Queda "más mono".

He encontrado, creo, una forma un poco chapucera de resolver el problema de las líneas en blanco:

@echo off
Setlocal EnableDelayedExpansion
del /q ubictmp.txt
for /f "tokens=1* delims=" %%a in (ubicaciones.txt) do echo %%a>>ubictmp.txt
del /q final.log
set fila=
set /a nfila=0
for /f "tokens=1 delims=/" %%a in (ubictmp.txt) do (
set /a nfila+=1
call :limpiaespacios "%%a"
call :comprob "!fila!" !nfila!
)
goto :eof
:comprob
for /f "skip=%2 tokens=1 delims=/" %%x in (ubictmp.txt) do (
call :limpiaespacios "%%x"
if "!fila!"==%1 echo !fila! >>final.log&goto :eof
)
goto :eof
:limpiaespacios
set ent=%~1
:bucle
if "%ent:~-1,1%"==" " set ent=%ent:~0,-1%&goto :bucle
set fila=%ent%
goto :eof

Digo que es un poco chapucera la solución porque se basa en algo que yo había detectado como un problema en casos de sustitución de cadenas literales en archivos (puedes verlo, por ejemplo, en Reemplazar cadena dentro de archivos de texto y consistía en que se eliminaban las líneas en blanco del archivo original. El primer FOR simplemente crea un archivo temporal (ubictmp.txt) que elimina las líneas en blanco y luego se trabaja con él en lugar de trabajar con el archivo original. Mira a ver si así ya funciona como quieres.

¡Gracias!

Me parece una solución perfecta para nuestro caso

He comprobado tambien  que  para si se da el caso de que alguno borra una ubicación, pero deja la descripción, esto daba un error que decía:

La sintaxis de comando no es correcta.

Pero simplemente poniendo en el primer for un delims=/,  esto se resuelve del todo

for /f "tokens=1* delims=/" %%a in (ubicaciones.txt) do echo %%a>>ubictmp.txt

Ya he comprobado que por algo estas como experto, creo que esta calificación se queda corto,

pero de todas formas ahí te dejo mi más sincero agradecimiento.

Me sorprendía un poco que la inclusión del "delims=/" en el primer FOR resolviera el problema. De hecho en la primera prueba (solo "comentarios" en una de las líneas, pero empezando en el comienzo de la línea) no se me daba el problema. Conseguí reproducirlo incluyendo una línea solo con "comentarios" pero con algunos espacios delante de los comentarios y en ese caso sí que lo resolvía el "delims=/". Luego me di cuenta que esa "solución" en realidad hace que en el ubictmp.txt ya no figuren los comentarios por lo que ya no sería necesario  incluir eso mismo en los otros dos FOR (aunque sí que debe figurar "delims=" para que no use el valor por  defecto que es el espacio). Aparece algo feo como "ECHO está desactivado." para la línea solo con comentarios y espacios por delante, que no afecta al resultado si solo se da un caso, pero sí que lo hace si hay más de uno, porque entonces pasará al final.log como si de una ubicación repetida se tratara. De nuevo esta pequeña tontería obliga a "retorcer" el código. He probado varias formas, aparentemente más sencillas, pero no me funcionaban. Al final esta parece funcionar bien:

@echo off
Setlocal EnableDelayedExpansion
del /q ubictmp.txt
for /f "tokens=1* delims=/" %%a in (ubicaciones.txt) do (
set control=%%a
set control=!control: =!
if not "!control!"=="" echo %%a>>ubictmp.txt
)
del /q final.log
set fila=
set /a nfila=0
for /f "tokens=1 delims=" %%a in (ubictmp.txt) do (
set /a nfila+=1
call :limpiaespacios "%%a"
call :comprob "!fila!" !nfila!
)
goto :eof
:comprob
for /f "skip=%2 tokens=1 delims=" %%x in (ubictmp.txt) do (
call :limpiaespacios "%%x"
if "!fila!"==%1 echo !fila! >>final.log&goto :eof
)
goto :eof
:limpiaespacios
set ent=%~1
:bucle
if "%ent:~-1,1%"==" " set ent=%ent:~0,-1%&goto :bucle
set fila=%ent%
goto :eof

Y gracias por las "flores". Empecé con esto porque para inscribirse en la página había que declararse "experto" en algo y opté por el MSDOS. Y he ido aprendiendo mucho en los intentos de ayudar a quién pedía ayuda en estos temas. Pero no tiene mérito porque realmente disfruto mucho con ello.

¡Gracias! 

Tienes razón, la verdad es que no se como pero lo de "ECHO está desactivado." ni me habia dado cuenta

Muchas gracias de nuevo

Ahora creo que ya está definitivo y bien, por lo menos le he realizados toda clase de pruebas que se me han ocurrido y no ha fallado en ninguna.

Buenas tardes

Acabo de ver un pequeño problema con la última versión que me mandas, y es que si tenemos dentro de la lista de ubicaciones, dos comentarios idénticos y solos, salen en la lista de duplicados, como que fuesen dos ubicaciones, si pones tres idénticos salen lo mismo que si fuesen ubicaciones, pero solo si están escritos pegados a la izquierda.

Ahora bien, he comprobado que los dos tienen que ser idénticos y no contener ningún espacio en blanco a la izquierda.

//datos

//datos

Ahora SI saldrían en la lista de duplicados

  //datos

  //datos

Ahora NO saldrían en la lista de duplicados

//datos

                  //datos

Y ahora por supuesto que tampoco salen en la lista de duplicados,

Si damos por bueno que todas las ubicaciones correctas deben tener en las posiciones segunda y tercera la combinación ":\" creo que podría servir el sustituir la línea:

if not "!control!"=="" echo %%a>>ubictmp.txt

por esta otra:

if not "!control!"=="" if "!control:~1,2!"==":\" echo %%a>>ubictmp.txt

Dime si puede valerte y si no vale cuéntame algo que pueda usarse como indicador de ubicación.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas