Buscar texto en archivos de una unidad y reemplazarlo
Sé que este tema se ha tocado muchas veces de maneras muy similares, pero no logro encontrar de qué manera realizarlo para mi proyecto. Lo que necesito es buscar en todo el disco F: y dentro de los archivos .txt que se encuentran en él la palabra TWELVE y reemplazarla por DORIAN, en todos los archivos TXT del disco F. Sé que se puede, pero no logro armar el Batch.
Prueba con esto:
@echo off set carpeta=F:\ set corig=TWELVE set csust=DORIAN pushd %carpeta% for /f "delims=" %%x in ('dir /s /b *.txt') do (find "%corig%" "%%x" >nul&&call :sustituir "%%x") popd goto :eof :sustituir Setlocal EnableDelayedExpansion del /q temp.txt>nul 2>&1 for /f "tokens=* delims=" %%a in ('type %1') do (set ANT=%%a&echo !ANT:%corig%=%csust%! >>temp.txt) copy /y temp.txt %1>nul Endlocal
Debo advertir que este BAT elimina las líneas en blanco de los archivos tratados y que no distingue mayúsculas y minúsculas dentro de los archivos tratados. Quiero decir que aunque el FIND del primer FOR si que distingue y por tanto si en un archivo existe la cadena "twelve" pero no la cadena "TWELVE" ese archivo no se tratará porque el FIND no lo encontrará. Pero si en uno de los archivos localizados por el FIND existe la cadena con minúsculas además de la cadena con mayúsculas cambiará ambas. Si alguno de estos dos inconvenientes te crea problemas dímelo y veremos si podemos/puedo resolverlo.
Hola, he probado con archivos copia obviamente, y me elimina líneas del código, te adjunto imágenes de las primeras líneas del archivo para que veas lo que hace.
cada ventana contiene su título como para que te guíes, me modifica de una manera mas drástica no sólo al principio sino también al final.
Cabe aclarar que al script lo he modificado para que busque TWELVE dentro de un archivo .vmix pero lo eh probado en archivos .txt pero no modifica la palabra, simplemente modifica el archivo en gral por dentro, y no termina modificando la palabra TWELVE sino que hace otra cosa, como lo verás en la imagen adjuntada.
Intuyo que el problema puede tener que ver con la longitud de las líneas. Me parece recordar, aunque ahora no encuentro "pruebas" de ello, que los archivos BAT tiene problemas cuando las líneas superan los 4096 bytes. Observo que la línea que empieza con <Input Type="4000"... parece haber desaparecido y se ve el fin del tag Input con </Input>. Si se confirmaran mis temores creo que tendrías que trabajar con PowerShell. Aunque no lo domino me encantaría intentar ayudarte con esta otra shell, mucho más potente aunque difícil de manejar, al menos al principio.
Voy a hacer algunas pruebas con líneas de esos tamaños y ya te diré algo más. Por tu parte intenta confirmarme (o desmentirme) si esas líneas "maltratadas" tienen muchos bytes y cuál es su longitud.
Ya he visto que el comando TYPE tiene una limitación de un máximo de 4095 caracteres por línea. Y en el BAT utilizo ese comando para listar el archivo. Voy a ver si puedo hacerlo de otra forma.
Creo que ya lo tengo. Lo cierto es que nunca, hasta hoy, tuve muy claro por qué a veces bastaba con poner el nombre del archivo en el IN del FOR y otras veces necesitaba usar el TYPE para conseguir el tratamiento línea a línea. Hoy no me ha quedado más remedio que enfrentarme al problema y creo que ya he comprobado que usaba el TYPE cuando el path del archivo tenía espacios, bien en alguna de las carpetas o en el propio nombre del archivo. Tampoco tenía muy claro para que servía el modificador USEBACKQ del comando FOR. Y creo que ya tengo ambas cosas.
Total que considero que sustituyendo la línea:
for /f "tokens=* delims=" %%a in ('type %1') do (set ANT=%%a&echo !ANT:%corig%=%csust%! >>temp.txt)
por esta otra:
for /f "usebackq tokens=* delims=" %%a in (%1) do (set ANT=%%a&echo !ANT:%corig%=%csust%! >>temp.txt)
debería resolverse.
De todas formas no descarto algunos otros problemas relacionados con la poca transparencia de los BAT respecto a algunos caracteres (como >, <, ", |, etc.) que están muy presentes en los XML. Mis pruebas las estaba haciendo con archivos TXT "normalitos"
Buen día, estuve probando el script, y es tal cual dices, tendré que trabajar con powershell para poder hacer lo que necesito, ya que reduje agresivamente la cantidad de texto para prueba y con texto reducido si funciona correctamente. El Script funciona, tengo que buscar la solución por otro lado nomás. Muchísimas gracias por tu tiempo, me sirve para otras cosas de todas formas. Que tengas un buen día.
¿Probaste con los cambios que sugería? Porque creo que esos cambios deberían conseguir que funcionara aún con líneas de más de 4096 caracteres al no hacer uso del comando TYPE. Si aún así falla cópiame la línea más grande que tengas para que pueda probar yo. He probado con líneas de XML bastante grandes y me ha funcionado.
No me consta que haya en todoexpertos un hilo para PowerShell pero, como te decía, puedo intentar echarte yo una mano. Supongo que el planteamiento es el mismo, sustituir una cadena por otra en un grupo de archivos, identificados por la extensión, por ejemplo
Sí. Puedes hacerlo así. Te sugiero que lo hagas en una ventanita "snippet". Por si no lo sabes se abre con el icono "<>".
bien, la verdad que excede la cantidad de caracteres, por lo que subí el archivo a google drive para que pruebes, es un txt
https://drive.google.com/file/d/10GRuVBlF75dPUxPi-kHsMsn4RaH1pRTW/view?usp=sharing
Está claro que no funciona bien con estas líneas tan grandes. Además he comprobado que elimina los espacios al comienzo de línea. Voy a probar con PowerShell y te cuento.
Ya tengo algo. Es un híbrido entre BAT y PS, que es la forma en que he trabajado alguna vez con PS. Utiliza el esqueleto del BAT con el que estamos trabajando y deja al PS la labor de sustitución de una cadena por otra.
@echo off set carpeta=F:\ set corig=TWELVE set csust=DORIAN pushd %carpeta% for /f "delims=" %%x in ('dir /s /b *.txt') do (find "%corig%" "%%x" >nul&&call :sustituir "%%x") popd goto :eof :sustituir copy /y %1 temp.txt>nul @PowerShell ^ (get-content 'temp.txt')^| foreach-object {$_ -replace "'%corig%'", "'%csust%'"} ^| set-content 'temp.txt' %End PowerShell% Copy /y temp.txt %1>nul
A mí me ha funcionado. Ya me contarás.
Una vez que estés conforme se puede prescindir del archivo TEMP.TXT y trabajar directamente sobre %1. Quedaría así:
@echo off set carpeta=F:\ set corig=TWELVE set csust=DORIAN pushd %carpeta% for /f "delims=" %%x in ('dir /s /b *.txt') do (find "%corig%" "%%x" >nul&&call :sustituir "%%x") popd goto :eof :Sustituir @PowerShell ^ (get-content '%1')^| foreach-object {$_ -replace "'%corig%'", "'%csust%'"} ^| set-content '%1' %End PowerShell%
- Compartir respuesta