Bat para crear copia de archivos txt considerando sólo las líneas que empiezan por la letra T

No tengo muchas experiencia en este mundillo, pero en alguna ocasión copiando de aquí y de allá, me he hecho algún bat majo, que me ha ahorrado horas y horas de trabajo.

Lo que tengo ahora mismo es un directorio con un montón de txt. Lo que querría es crear una copia de cada uno de los archivos en otra ubicación, pero que el nombre de este nuevo txt sea el contenido de la primera línea (si está vacío de la segunda) y que dentro del archivo solo se mantengan las líneas que empiezan por la letra T.

Es decir si el archivo B0001.txt tiene en la primera línea la frase "cocina 100 4D8", el nuevo archivo que se ubicaría en una carpeta diferente a la original(si esto es complicado se puede dejar en la misma y losuebl luego a mano) sería "cocina 100 4D8.txt", y si su contenido original era:

"menú lunes

3 platos

T200

Postre sencillo

T150

Sin cafe

T450"

El del nuevo archivo sería :

"T200

T150

T450"

Muchísimas gracias por vuestro tiempo y la ayuda que intenteis prestarme.

1 respuesta

Respuesta
1

Me han surgido algunas dudas respecto a lo que planteas:

  1. ¿Puede darse el caso de que se repita el nombre de alguno de los nuevos archivos? Es decir, ¿puede ocurrir que la primera línea no vacía de los archivos a tratar tenga el mismo contenido en más de un archivo?
  2. Supongo que las comillas del principio y final de los archivos de ejemplo no forman parte de los archivos
  3. ¿Puede darse el caso de que la primera línea esté rellena con espacios en lugar de vacía?
  4. La T que distingue las líneas a extraer, ¿tiene qué ser mayúscula o puede ser minúscula?

En todo caso esta podría ser una primera versión del BAT que buscas:

@echo off
Setlocal EnableDelayedExpansion
set origen=<carpeta de los archivos a tratar>
set destino=<carpeta donde dejar los archivos nuevos>
set nombre=
pushd %origen%
for /f "tokens=*" %%z in ('dir /b *.txt') do (
   set ind=N
   del /q tmp.txt>nul 2>&1
   for /f "usebackq tokens=*" %%a in (%%z) do (
      if "!ind!"=="N" set ind=S&set nombre=%%a
      set lin=%%a
      if "!lin:~0,1!"=="T" echo %%a>>tmp.txt
      )
      Echo copy tmp.txt "%destino%\!nombre!.txt"
   )
Popd

Para la variable ORIGEN debes poner el path completo de la carpeta en la que están los archivos que quieres tratar y para DESTINO el path de la carpeta donde quieres dejar los archivos creados. Esta versión no vale para la "t" ni filtra que la primera línea de los archivos no vaya a espacios (sí que filtra que no esté vacía). Prueba y nos dices

Perdón, tienes que quitar el ECHO que precede al COPY. Es un comando de "depuración" para ver el comando antes de que se ejecute y se me olvidó quitarlo.

Buenos días, muchas gracias por tu atención!1- No debería haber nombres repetidos, pero debido al desorden que hay desgraciadamente se podrá dar el caso. Podría solucionarse añadiendo un-1, -2, -3... después del nombre ¿?

2- Supones bien, no es parte del código del texto, era solo para el ejemplo de la pregunta.

3- Le he dado una vuelta al tema de como recoger el nombre del archivo, y creo que la derecha va ser directamente si cogemos siempre lo que hay en la segunda línea. De forma generalizada la primera línea tiene el carácter %

4- La "T" siempre estará en mayuscula.

He probado el bat actual, pero no me funciona. En la imagen inferior puedes ver que he ubicado en una misma carpeta del escritorio la carpeta de origen "ORIGEN"  y la carpeta destino "TABLA HERRAMIENTAS". También puedes ver el código tal cual lo he dejado, sin el ECHO del final, y con las ubicaciones de destino y origen. Se ejecuta super rápido, pero no hace nada. 

MUCHISIMAS GRACIAS UNA VEZ MÁS.

Se me olvidó advertirte que los caracteres <> incluidos en las variables ORIGEN y DESTINO no forman parte de los valores. Pretendían ser solo una forma de indicar que se trataba de valores "personalizables". Quítalos y vuelve a probar.

He cometido ese error, pero también lo he intentado hacer sin los caracteres <> pero el resultado ha sido el mismo. Gracias!

Vuelve a mostrarme el bat. A mí me funciona. Pero prueba ya, si quieres, esta versión que incluye el tratamiento de nombres iguales:

@echo off
Setlocal EnableDelayedExpansion
set origen=d:\carpeta prueba\alabamaCarp
set destino=d:\carpeta prueba\p\pba-msdos - ahora-kk
set nombre=
set /a maxrep=10
pushd %origen%
for /f "tokens=*" %%z in ('dir /b *.txt') do (
   set ind=N
   del /q tmp.txt>nul 2>&1
   for /f "usebackq tokens=*" %%a in (%%z) do (
      if "!ind!"=="N" set ind=S&set nombre=%%a
      set lin=%%a
      if "!lin:~0,1!"=="T" echo %%a>>tmp.txt
      )
      call :nombrar
      copy tmp.txt "%destino%\!nombre!.txt"
   )
popd
:nombrar
if exist "%destino%\!nombre!.txt" (
   for /l %%n in (1, 1, %maxrep%) do if not exist "%destino%\!nombre!_%%n.txt" (set nombre=!nombre!_%%n&goto :eof)
   )

Dejo los valores con los que pruebo en mi entorno por si te dan una pista de como relleno ORIGEN y DESTINO

Ahora mismo lo tengo así:

He ubicado la carpeta en la raíz de la unidad C, y he puesto barra baja entre la separación de las palabras. No se cual es la torpeza que estoy cometiendo. En la carpeta ORIGEN contengo archivos del tipo txt. Gracias!

Respecto a lo que dices de que la primera línea suele ser un %, podríamos hacer que siempre se empezara a leer en la segunda sin más que incluir un SKIP=1 en el segundo FOR /F. Quedaría así:

   for /f "usebackq skip=1 tokens=*" %%a in (%%z) do (

¿Cómo ejecutas el bat? ¿Desde una ventana CMD o directamente desde el explorador de Windows? Si es de esta segunda forma ponle un PAUSE al BAT después del POPD para poder ver si sale algún mensaje. Si es desde ventana CMD muéstrame un pantallazo

He sustituido la línea del segundo For por la que me acabas de facilitar, pero no se lo que hace, pues me sigue sin funcionar

Lo estaba haciendo ejecutando directamente el archivo .bat.

He probado a llamarlo desde CMD pero no me da ninguna información.

También he incluido el PAUSE después del POPD pero no veo que me diga nada.

Incluso he quitado el ECHO OFF del inicio, pero no veo nada.

Siento estar mareándote tantísimo, pero no entiendo que está fallando.

Muchas gracias.

Creo que lo primero que tenemos que hacer es asegurarnos que estamos ejecutando el bat. Para ello te sugiero que incluyas, después del ECHO OFF y manteniendo el PAUSE si lo ejecutas desde el Explorador, algo como

Echo Se ha lanzado el BAT

Lanza el BAT y comprueba que sale el mensaje. Si no sale nada habría que pensar que el usuario no tiene permisos de ejecución, o algo así.

Lo único raro que veo es que una vez ejecuto el bat "PRUEBAS.BAT" no hace lo deseado, pero cambia la ruta de línea de comandos. Se mete en ORIGEN.

Si que sale el mensaje  de "se ha lanzado el bat"

GRACIAS!

No acabo de entender. Ya sale el mensaje. Es un buen comienzo. ¿Y qué más?

¿Por qué las "

Se ha comido una parte de mi mensaje. Preguntaba que por qué me dabas las

Se ha vuelto a comer la misma parte. En fin, supongo que entiendes lo que no me deja poner el editor de la página.

Las comillas, mala manía que tiene uno de entrecomillar todo.

Como puedes ver lanza el BAT, pero después no hace nada.

Como dije al inicio no tengo mucha idea, se hacer pequeños cambios y reciclar códigos de otros. Pero ahora mismo no se dar con el motivo de que no haga lo que queremos.

¿Qué puedo hacer?

Muchas gracias por tu atención, no me canso de repetirlo: gracias.

Vamos a ver. Ya hemos comprobado que entra al bat. El que no se vea nada más no significa que no esté haciendo nada pero tampoco que esté haciendo algo.

Vamos a incluir ahora un ECHO para ir viendo lo que va haciendo. Antes del comando SET Ind=N inserta el comando

Echo Tratando el archivo %%z

Con esto veremos si está tratando archivos

Buenas, perdona que no te haya podido contestar antes.

Creo que aquí podrás sacar conclusiones. 

Parece que entra en el For, ve el primer archivo de la carpeta que es el 19999.txt, pero luego no hace nada, ni si quiera se llega a ver el z4 que le he metido dentro del for.

Muchas gracias.

Veamos. Los ECHO's anteriores al FOR no aportan mucho pero, sobre todo, debes entender que el %%z que incluía en el ECHO que te proponía, solo valen dentro del FOR porque %%z es la propia variable del primer FOR. Tú los has "ubicado" añadiendo un número pero el %%z no aporta nada en los ECHO externos a ese FOR. Por eso no ves el z4 que dices, porque es el único que está dentro del FOR y por eso en ese ECHO la variable %%z tiene como valor un nombre de archivo.

Por tanto seguimos avanzando, pasito a pasito. Ya sabemos que identifica un archivo, de nombre 19999.txt, que se encuentra en C:\PRUEBAS\ORIGEN. El hecho de que no salgan más mensajes de los de dentro del primer FOR me da a entender que el BAT se "pierde" en el tratamiento de ese primer archivo detectado.

Vamos a seguir viendo lo que hace con esta versión de depuración:

@echo off
Setlocal EnableDelayedExpansion
set origen=C:\PRUEBAS\ORIGEN
set destino=C:\PRUEBAS\TABLAHERRAMIENTAS
set nombre=
set /a maxrep=10
pushd %origen%
for /f "tokens=*" %%z in ('dir /b *.txt') do (
   echo Tratando archivo %%z
   pause
   set ind=N
   del /q tmp.txt>nul 2>&1
   for /f "usebackq tokens=*" %%a in (%%z) do (
      echo Tratando linea /%%a/ del archivo %%z
      if "!ind!"=="N" set ind=S&set nombre=%%a
      set lin=%%a
      if "!lin:~0,1!"=="T" echo %%a>>tmp.txt
      )
      call :nombrar
      copy tmp.txt "%destino%\!nombre!.txt"
   )
popd
:nombrar
if exist "%destino%\!nombre!.txt" (
   for /l %%n in (1, 1, %maxrep%) do if not exist "%destino%\!nombre!_%%n.txt" (set nombre=!nombre!_%%n&goto :eof)
   )

Le he quitado el SKIP=1 al bucle interno por si distorsiona en este punto.

Además de copiarme el pantallazo de lo que te sale puedes incluir un DIR /B *.TXT de la carpeta C:\PRUEBAS\ORIGEN.

No sé si estás acostumbrado al uso de Teamviewer. Si es así puedo conectarme remotamente a tu equipo y hacer las pruebas yo directamente, si es que me pillas sin mucho que hacer.

Perdón, añade otro PAUSE detrás del ECHO del segundo FOR

Si no saliera ningún "Tratando línea /.../ del archivo 19999.txt" entonces haz un TYPE 19999.txt para que pueda ver que contiene ese archivo porque ahí estaría el problema.

Si señor! Ahora hemos/has avanzado kilómetros.

He visto como va recorriendo los FOR, y al acabar con el archivo 199999.txt ha generado el primer archivo en la carpeta destino.

La pega es que ha cogido el nombre de archivo de la primera línea. Creo que en algún lado me dijiste que había que hacer para que coja el valor de la segunda línea, que sería lo idóneo.

Voy a echar un vistazo. Muchas gracias. Eres grande!

He intentado introducir este cambio en el segundo FOR como me dijiste ayer, pero parece que ahora no encuentra la ruta destino para copiar el archivo:

Gracias!

 for /f "usebackq skip=1 tokens=*" %%a in (%%z) do (

Es un poco raro. Ahora parece tratar varios archivos, no se queda en el primero. Pero eso no puede tener que ver con el hecho de haber incluido ECHO's de depuración.

En todo caso veo que parece haber un problema en la ruta del COPY. Para intentar investigar un poco ese punto inserta los comandos:

Echo copy tmp.txt "%destino%\!nombre!.txt"
Pause

antes del comando

Copy tmp.txt "%destino%\!nombre!.txt"

Aquí lo tienes!

No sé a que se puede deber, pero unos archivos los copia en la carpeta destino y otros no.

Está claro. Windows/MSDOS no permiten el carácter "/" en los nombres de archivo.

Cierto, pues de 580 que tengo en una de las 20 carpetas que tengo que tratar, solo se libran 64.

Podría pasar primero un bat que haga que todos los caracteres / de estos archivos sean sustituidos por un - ¿?

Se puede incluir en el bat un cambio de caracteres. Te lo pongo para cambiar el "/" por un "-" y ya quito algunos ECHO's de depuración:

@echo off
Setlocal EnableDelayedExpansion
set origen=C:\PRUEBAS\ORIGEN
set destino=C:\PRUEBAS\TABLAHERRAMIENTAS
set nombre=
set /a maxrep=10
pushd %origen%
for /f "tokens=*" %%z in ('dir /b *.txt') do (
   echo Tratando archivo %%z
   pause
   set ind=N
   if exist tmp.kkk del /q tmp.kkk>nul 2>&1
   for /f "usebackq tokens=*" %%a in (%%z) do (
      if "!ind!"=="N" set ind=S&set nombre=%%a
      set lin=%%a
      if "!lin:~0,1!"=="T" echo %%a>>tmp.kkk
      )
      call :nombrar
      set nombre=!nombre:/=-!
      Echo copy tmp.kkk "%destino%\!nombre!.txt"
      Pause
      Copy tmp.kkk "%destino%\!nombre!.txt"
   )
Popd
:Nombrar
if exist "%destino%\!nombre!.txt" (
   for /l %%n in (1, 1, %maxrep%) do if not exist "%destino%\!nombre!_%%n.txt" (set nombre=!nombre!_%%n&goto :eof)
   )

He cambiado el nombre del archivo temporal de TMP.TXT a TMP. KKK porque si se mantiene la extensión TXT puede ser uno de los tratados por el primer FOR y eso puede dar algún problemilla.
Prueba a ver como va.

Menudo lujo! Lo tienes!!!!!!!!

De esta primera carpeta de 580 archivos, ha copiado 570.

Puede ser que los archivos que no tengan ninguna "T" los ignore, verdad¿? Me viene que sea así, es por confirmar la diferencia de esos diez archivos.

MUCHAS GRACIAS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Pues sí, el archivo TMP. KKK no se creará si no hay ninguna línea que empiece por "T" y por tanto en ese caso el COPY no hará nada.

Tendrás que probar también el caso en que ya exista el archivo de destino porque se haya creado previamente. En ese caso debería añadirse al nombre un "_n" con "n" entre 1 y 10 (lo controla la variable MAXREP).

Bueno. No entiendo por qué no funcionaba al principio porque realmente no ha habido ningún cambio sustancial entre la versión inicial y esta última, aunque sí algunas mejoras.

¡Gracias! XD

A donde te mando el jamón? 

Fue un placer. Feliz Navidad y esas cosas.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas