Programación en batch, creación de Script

Estoy intentado hacer un script que consiste en ir a una carpeta y coger todos los archivos que hayan, y uno a uno acceder al archivo, y renombrar ese mismo archivo con una parte de texto de la primera línea que hay:

Por ejemplo:

El archivo Tsc58034. Arcaec -----> entrar en ese archivo -----> primera línea -----> 0124579302530141 -----> renombrar el fichero con parte del texto de la primera línea -----> 79302530

Lo tengo hecho hasta el momento es lo siguiente:

Le paso por parámetro la ruta de la carpeta la cual contendrán los ficheros, y creo un listado de los ficheros que existen en esa carpeta. Después creo una variable con el nombre del fichero más la ruta de dónde está, para poder hacer un findstr, y numerar las líneas para luego con la salida de ese comando quedarme con la primera línea. Esto lo estoy intentando meter en la variable nombreFichero, para posteriormente renombrar el fichero que estoy tratando con el nombre que quiero poner. Pero si ejecuto el script, no me funciona la parte de findstr... En cambio si cojo solo la parte del código de findstr y lo ejecuto directamente en la una consola de CMD, sí me hace ese findstr, ¿alguien me podría explicar el porque de esto, por favor?

Os dejo la parte del código que tengo hecho hasta el momento, saludos y gracias de ante mano.

Setlocal enabledelayedexpansion
:@echo off:
set ruta=%1
dir %ruta% /B > .\listado.txt

for /F "tokens=*" %%X in (listado.txt) do (
set temporal=%%X
call :ficheros
)
goto fin

:Lee el fichero y mete en una variable temporal la primera línea:
:Ficheros

set nombreFichero=(findstr /n "." %ruta%%temporal% | findstr "^1:")
Echo este es el nombre del fichero %nombreFichero:~6, 18%

:Fin

del .\listado.txt

1 respuesta

Respuesta
1

Sin entrar a fondo en si tu script hace o no lo que pretende, porque cada uno tiene su propia manera de "programar", si que puedo decirte que la única manera que yo conozco de guardar en una variable el resultado de un comando es a través de un FOR. Por extraño que parezca (yo he caído repetidas veces en esa misma "trampa") no hay manera de asignar mediante un SET el resultado de un comando a una variable. Además creo que te falta el carácter "\" para separar la ruta del nombre del archivo en %ruta%%temporal%. De modo que deberías sustituir:

set nombreFichero=(findstr /n "." %ruta%%temporal% | findstr "^1:")
Echo este es el nombre del fichero %nombreFichero:~6, 18%

Por algo como

for /F "tokens=*" %%A in ('findstr /n "." "%ruta%\%temporal%" ^| findstr "^1:"') do (
set nombreFichero=%%A
Echo este es el nombre del fichero %nombreFichero:~6, 18%
)

No digo que con esto funcione (de hecho veo que todavía no has incluido el comando de "rename", de lo que deduzco que estás en los pasos previos) pero creo que te permitirá avanzar. Si te choca el "^|" que aparece en el comando del FOR te diré que es para "escapar" el carácter "|" y que funcione el comando.

Si quieres que sigamos con tu "diseño" y necesitas más ayuda no dudes en seguir con este hilo.

Suerte.

¡Gracias! Lo probaré cuando tenga un ratillo! 

¿Pudiste probarlo?

Si necesitas algún tipo de ayuda no dudas en decírmelo y vemos si puedo aportar algo.

Sí, lo he modificado en algunas cosas, esta casi casi, pero no he dicho nada porque no llevo sin internet desde el miércoles, y estoy escribiendo desde el movil.

¡Hombre! Tampoco tienes obligación de decir nada. Pero tenía curiosidad.

Espero que vuelvas a tener Internet pronto y que lo completes a tu gusto.

Sí, cuando lo tenga montado os lo pondré para ver si alguien lo puede optimizar o por si lo quieren de ejemplo. :) y por la ayuda recibida, claro! 

Buenos días.

El Script esta casi casi hecho, pero hay un problema que si encontramos algún fichero que se llama igual, no me lo renombra bien, y he intentado realizar una condición if y dentro de este un for para hacer de contador y poner el nombrefichero_1, nombrefichero_2, nombrefichero_3, etc... y no me sale muy bien, a ver si alguien me puede identificar el fallo, porque no lo veo

Os pongo ejemplo de lo que intento hacer con imágenes para que se vea más claro:

Estos son los ficheros que necesito tratar.

El contenido de los ficheros, por ejemplo es este, del cual solo me interesa la primera línea, y para renombrar el fichero necesito realizar la siguiente estructura de nombre, dd + Código + fecha (ddmmaaaa) + 01 + . T65 + hhmm

Y el resultado que obtengo es el siguiente, pero cuando hay un fichero que tiene el mismo nombre, no me actualiza bien los ficheros, el ".T65+hhmm" es la hora en la que se renombra el fichero, y por eso no me los renombra bien y quería ponerle la terminación _1, _2, _3 en caso de que coincida el nombre con el anterior.

Por otra parte no me elimina bien el fichero_temporal.txt que creo con la lista de ficheros que hay que tratar, y no veo razón de por qué no lo borra...

Gracias y un saludo.

Para ejecutar el script pongo lo siguiente en una CMD ---> proceso.bat c:\pruebas\

En la carpeta c:\pruebas\ tengo los ficheros sin tratar.

Os pongo hasta donde tengo hecho del script:

:Hay que pasar por parámetro la ruta donde se encuentran los ficheros a tratar:
setlocal enabledelayedexpansion
@ECHO off:
IF EXIST listado_temporal.txt del /F listado_temporal.txt
SET ruta=%1
DIR %ruta% /B > .\listado_temporal.txt
FOR /F "tokens=*" %%X IN (listado_temporal.txt) DO (
SET temporal=%%X
CALL :ficheros
)

:ficheros
FOR /F "tokens=*" %%A IN ('listado_temporal.txt ^| findstr /n "." "%ruta%%temporal%" ^| findstr "^1:"') DO (
SET nombreFichero=%%A
SET formato="!nombreFichero:~7,4!!nombreFichero:~17,2!!nombreFichero:~15,2!!nombreFichero:~11,4!"
CALL :renombrar
)
CALL :fin

:renombrar
::con este bucle sacamos la hora con formato de dos dígitos en caso de que sea antes de AP (01, 02, 03,... horas)
FOR /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set hora=%%a)
::Renombramos el fichero, comprobando si el fichero existe, y si existe lo renombramos con un _1, _2, _3, etc..
set contador=0
IF %ruta%%temporal%==dd%formato%01.T65!hora!%time:~3,2% (set /A contador=contador+1 && REN %ruta%%temporal% dd%formato%01.T65!hora!%time:~3,2%_%contador%) ELSE (REN %ruta%%temporal% dd%formato%01.T65!hora!%time:~3,2% && set contador=0)

:fin
DEL .\listado_temporal.txt

He copiado y pegado tu BAT y lo he intentado ejecutar, sin tener muy claro si hace lo que pretendes, para ver que ocurría. Me da un error en el FINDSTR porque "No se puede abrir xxxxx" siendo xxxxx lo que corresponde a %ruta%%temporal% y se queda "colgado". Parece claro que debería decir %ruta%\%temporal%.

Corregido lo anterior ya no da el error pero se queda colgado. Realmente no entiendo lo que intentas con

'listado_temporal.txt ^| findstr /n "." "%ruta%\%temporal%" ^| findstr "^1:"'

Ya tienes el nombre de uno de los ficheros en la variable %temporal%, supongo que con esto quieres capturar el texto de la primera línea del archivo, pero para eso bastaría

FOR /F "tokens=*" %%A IN (%ruta%\%temporal%) DO (...

Por concretar, en el ejemplo que pones del archivo dd006511052015. T65150000 cuya primera fila es 501080065320150511, ¿qué nombre quieres darle a ese archivo?

Del bat deduzco:

! NombreFichero:~7,4! -> 6532
!nombreFichero:~17,2! -> 1
! NombreFichero:~15,2! -> 51
! NombreFichero:~11,4! -> 0150

Por tanto sería algo como dd"65321510150"01. T65 etc. Pero fíjate que %formato" lleva las comillas incluidas y eso puede estropear toda la variable.

Otras cosas: CALL :FIN creo que debería ser GOTO :FIN. Cuando quieras poner fin a una rutina o que devuelva el control al punto desde el que se la llamó debes poner GOTO :EOF. Al no usarlo en la rutina FICHEROS ni RENOMBRAR se encadena la ejecución propia con lo que viene después. Por tanto FICHEROS llama a RENOMBRAR y esta continua con :FIN (comando DEL). El final del BAT se interpreta como un retorno de RENOMBRAR que devolvería el control al punto de llamada desde FICHEROS, por lo que a continuación ejecutaría el CALL :FIN (de nuevo el comando DEL). En fin, bastante caótico.

Depura eso un poco y luego ya vemos que ocurre con los añadidos secuenciales al nombre si ya existe.

Se me olvidaba. Dado que creas el archivo listado_temporal.txt con una redirección ">" no es necesario que te preocupes del borrado de ese archivo. Esa redirección lo reescribe, borrando lo que hubiera antes.

Revisando tu mensaje original he entendido un poco lo que quieres hacer con el findstr. Creo que no hace falta complicarlo tanto. El FOR /F ya trata los archivos línea a línea, por tanto se puede conseguir que solo trate la primera línea si después del tratarla se hace un "GOTO :EOF" en el FOR de la rutina :FICHEROS

Y ya entrando en los renombrados secuenciales, si el nombre que vas a asignar ya existe (pero solo el nombre, sin el añadido del "_n") le asignas el nombre con el añadido "_1". Si el siguiente tiene el mismo nombre y ya existe le volverás a añadir un "_1" con lo que te dirá que ya existe. Por tanto no basta con comprobar si ya existe el nombre que "has diseñado" sino también cuál es el mayor "n" que tienen los que tengan ese nombre. A ese "mayor n" se le sumaría 1 y se renombraría añadiendo ese nuevo "_n". Tendrías que crear un bucle de comprobación de existencia de nombre_n incrementando n cada vez que exista. Cuando ya no exista haces el renombrado.

¿Algún avance?

Perdón, es me ha colado una "l" de más, dumen.

Lo tengo en el trabajo, el script he modificado cosas, pero no lo he terminado del todo

A ver que te parece esta solución:

Setlocal enabledelayedexpansion
@ECHO off
IF EXIST listado_temporal.txt del /F listado_temporal.txt
SET ruta=%1
DIR %ruta% /B > .\listado_temporal.txt
FOR /F "tokens=*" %%X IN (listado_temporal.txt) DO (
SET temporal=%%X
CALL :ficheros
)
GOTO :FIN
:ficheros
FOR /F "tokens=*" %%A IN (%ruta%\%temporal%) DO (
SET nombreFichero=%%A
SET formato=!nombreFichero:~7,4!!nombreFichero:~17,2!!nombreFichero:~15,2!!nombreFichero:~11,4!
CALL :renombrar
GOTO :EOF
)
:renombrar
::Con este bucle sacamos la hora con formato de dos dígitos en caso de que sea antes de AP (01, 02, 03,... horas)
FOR /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set hora=%%a)
::Renombramos el fichero, comprobando si el fichero existe, y si existe lo renombramos con un _1, _2, _3, etc..
set contador=1
IF EXIST %ruta%\dd%formato%01.T65!hora!%time:~3,2% (
:bucle
IF EXIST %ruta%\dd%formato%01.T65!hora!%time:~3,2%_!contador! (set /a contador=contador + 1&goto :bucle)
REN %ruta%\%temporal% dd%formato%01.T65!hora!%time:~3,2%_!contador!
) ELSE REN %ruta%\%temporal% dd%formato%01.T65!hora!%time:~3,2%
GOTO :EOF
:fin
REM DEL .\listado_temporal.txt

Me he ajustado, más o menos, a tus líneas de "acción".

Dime si te funciona.

Buenas tardes.

Yo tengo algo parecido siguiendo los consejos que me diste, pero me pierdo un poco al intentar hacer la condición IF EXIST, cuando se refiere ha hacer el bucle para mirar si existe el fichero para renombrarlo o no, he estado mirando por internet para entender mejor la condición, y no he visto en el IF EXIST, que tenga la opción del ELSE, supongo que también se podrá utilizar el ELSE con este tipo de IF...

Igualmente he probado el script que me has pasado y me sale que falla a la hora de renombrar el fichero, te pongo un screenshot, porque parece que no coge algún valor correctamente a la hora de renombrar el fichero.

setlocal

Igualmente del script he cambiado de la variable contador y la variable hora los "!" por los de "%" ya que creo que al estar fuera del FOR se deberían de expresar así %contador% y %hora%, no sé si he hecho bien, (igualmente de la otra forma tampoco funcionaba).


enabledelayedexpansion
@ECHO off:
IF EXIST listado_temporal.txt del /F listado_temporal.txt
SET ruta=%1
DIR %ruta% /B > .\listado_temporal.txt
FOR /F "tokens=*" %%X IN (listado_temporal.txt) DO (
SET temporal=%%X
CALL :ficheros
)
GOTO :FIN
:ficheros
FOR /F "tokens=*" %%A IN (%ruta%\%temporal%) DO (
SET nombreFichero=%%A
SET formato=!nombreFichero:~7,4!!nombreFichero:~17,2!!nombreFichero:~15,2!!nombreFichero:~11,4!
CALL :renombrar
GOTO :EOF
)
:renombrar
::con este bucle sacamos la hora con formato de dos dígitos en caso de que sea antes de AP (01, 02, 03,... horas)
FOR /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set hora=%%a)
::Renombramos el fichero, comprobando si el fichero existe, y si existe lo renombramos con un _1, _2, _3, etc..
set contador=0
IF EXIST %ruta%\dd%formato%01.T65%hora%%time:~3,2% (
:bucle
IF EXIST %ruta%\dd%formato%01.T65%hora%%time:~3,2%_%contador% (set /a contador=%contador% + 1 & goto :bucle)
REN %ruta%\%temporal% dd%formato%01.T65%hora%%time:~3,2%_%contador%
) ELSE REN %ruta%\%temporal% dd%formato%01.T65%hora%%time:~3,2%
GOTO :EOF
:fin
REM DEL .\listado_temporal.txt


Saludos

En el caso que remarcas del pantallazo la razón del error es que el nuevo nombre tiene espacios incluidos, en cuyo caso tendría que ir entre comillas. Pero poner las comillas en el comando puede tener otras consecuencias que habría que revisar.

En mi entorno de pruebas el BAT funciona pero no se puede descartar que, además del problema de los espacios incluidos en el nuevo nombre pudiera haber alguna otra circunstancia que explique que no te funcione. Respecto al uso de "!" o "%" para acotar las variables lo probaré mañana si tengo un rato y ya te diré. Es cierto que están fuera del bucle FOR pero están dentro del bucle construido por mí precisamente para cambiar el valor del contador y sospecho que eso hace que tengan que considerarse del tipo local y no global.

¡Gracias! 

Acabo de probar y tienes razón con los "%" y los "!" de las variables hora y contador. No hace falta usar "!" (o eso parecen demostrar mis pruebas).

Habría que decidir si se permiten espacios en las primeras líneas de los archivos y si se permiten espacios en los nombres antiguos de los archivos o en los componentes de la "ruta" porque eso puede afectar al código (no solo en la necesidad de las comillas sino, por ejemplo, en tener que usar el comando TYPE para revisar las líneas de los archivos).

Ya me dirás.

En el contenido de los archivos, en la primera línea que es la que interesa no contienen espacios, directamente hay otro salto de línea con la continuación del contenido del fichero.

Los nombres antiguos de los ficheros no contienen espacios.

En la ruta de los fichero sí puede haber espacios hasta llegar al fichero en cuestión.

Saludos.

En esas condiciones el siguiente bat debería funcionar como quieres:

@echo off
Setlocal enabledelayedexpansion
dir %1 /b > .\listado_temporal.txt
set ruta=%~1
for /f "tokens=*" %%x in (listado_temporal.txt) do (
set temporal=%%x
call :ficheros
)
goto :fin
:ficheros
for /f "tokens=*" %%a in ('type "%ruta%\%temporal%"') do (
set nombrefichero=%%a
set formato=!nombrefichero:~7,4!!nombrefichero:~17,2!!nombrefichero:~15,2!!nombrefichero:~11,4!
call :renombrar
goto :eof
)
:renombrar
::Con este bucle sacamos la hora con formato de dos dígitos en caso de que sea antes de ap (01, 02, 03,... horas)
for /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set hora=%%a)
::Renombramos el fichero, comprobando si el fichero existe, y si existe lo renombramos con un _1, _2, _3, etc..
set contador=1
if exist "%ruta%\dd%formato%01.t65%hora%%time:~3,2%" (
:bucle
if exist "%ruta%\dd%formato%01.t65%hora%%time:~3,2%_%contador%" (set /a contador=contador + 1&goto :bucle)
ren "%ruta%\%temporal%" dd%formato%01.t65%hora%%time:~3,2%_%contador%
) else ren "%ruta%\%temporal%" dd%formato%01.t65%hora%%time:~3,2%
goto :eof
:Fin

No sé si el "formato" es exactamente lo que quieres o habría que hacer un retoque. Por lo demás en mis pruebas parece ir bien. Por supuesto, si la ruta contiene espacios hay que pasársela al bat entre comillas.

Ya me dirás,

GGG

Buenas tardes.

Lo acabo de probar y no renombra bien los ficheros cuando están repetidos los nombres.

No sé de donde sale ese espacio en blanco, ya que creo que esa parte de código corresponde a esta parte de código:

Estoy intentando comprender por qué aparece ese espacio, pero no veo la causa...

De hecho, en el "IF EXIST" ya aparece el nombre del fichero con el espacio.

Después en la sentencia ren c:\pruebas\dd30250805201501.T651428" dd5320  08150501.T651219_1

¿No debería de ser así? ya que el comando ren parece que lo renombra a con otro nombre_1 distinto al original.

ren c:\pruebas\dd30250805201501.T651428" dd30250805201501.T651428_1

Como te decía la variable "formato" es crítica y yo creo que no está conformada como tú esperas. Si me dices cual es el contenido de la primera línea del archivo dd30250805201501. T651428 creo que podré demostrarte que "nombrefichero:~17,2" (segundo componente del formato) está en blanco. La cuenta de comienzo de la subcadena empieza en cero, de modo que 17 es el décimooctavo carácter de la cadena "nombrefichero". Fíjate en lo que te decía en mi primer mensaje del 8 de junio donde intentaba desmenuzar el "formato".

¡Venga, que esto ya está a punto de caramelo!

Y haz un type del bat, porque me parece que has hecho algún retoque en cuanto al formato, ¿no? Si respetamos el original que era, si mal no recuerdo:

set formato=!nombrefichero:~7,4!!nombrefichero:~17,2!!nombrefichero:~15,2!!nombrefichero:~11,4!

Para un contenido de 501080065320150511 debería salir

6532...

En lugar de

5321...

Creo que lo has retocado así:

formato=! Nombrefichero:~8,4! Nombrefichero:~18,2! Nombrefichero:~16,2! Nombrefichero:~12,4!

Entonces la explicación sería que la primer línea finaliza en varios espacios en blanco (al menos dos) y la componente "nombrefichero:~18,2" del formato es la que incluye esos dos espacios en blanco.

¿Me equivoco?

¿Lo damos por resuelto?

GGG

Justo hoy cojo 10 días de vacaciones, intentaré mirármelo en estos días, pero no sé si podré, ya que me voy a Ibiza (soy de BCN) y no sé si me dejarán tranquilo para poder hacerlo.

Si hago algún avance lo notificaré!

Saludos!

No hay prisa. Es solo que me sorprendía que estando ya tan lanzados en el asunto no hubieras dicho nada. Pero esa ese una buena razón.

Disfruta de las vacaciones.

Es que es una tarea del trabajo, que tengo que hacer cuando pueda, no es urgente y lo voy haciendo a ratos "libres"

Por eso no lo he podidO continuar todavía.

Saludos.

Perfecto. Cuando tengas algo más que decir lo haces y ya está.

Buenas tardes.

Al final se ha decidido dejar el script más sencillo, para coger los archivos y renombrarlos, sin tener en cuenta la posibilidad de que pudieran haber duplicados.

Con lo que ya se puede dejar el tema por zanjado. Dejo el Script como lo he finalizado por si a alguien le pudiera servir.

::Hay que pasar por parámetro la ruta donde se encuentran los ficheros a tratar:
@echo off
setlocal enabledelayedexpansion
::Asigna la ruta de lso ficheros a la variable "ruta"
set ruta=%~1
IF "%ruta%"=="" echo has de indicar la ruta de los ficheros.
IF not "%ruta%"=="" (
set anio=%date:~6,5%
set mes=%date:~3,2%
set dia=%date:~0,2%
::Crea un fichero auxiliar listando todos los ficheros del directorio indicado.
dir %1 /b > .\listado_temporal.txt
::Bucle por cada linea "nombre del fichero a renombrar" del fichero uxiliar hace el tratamiento.
for /f "tokens=*" %%x in (listado_temporal.txt) do (
set temporal=%%x
call :ficheros
)
goto :fin
:ficheros
for /f "tokens=*" %%a in ('type "%ruta%\%temporal%"') do (
set nombrefichero=%%a
set formato=!nombrefichero:~4,4!%dia%%mes%%anio%
set rutayFichero="%ruta%\dd%formato%01.t65%hora%%time:~3,2%"
call :renombrar
goto :eof
)
:renombrar
::con este bucle sacamos la hora con formato de dos dígitos en caso de que sea antes de ap (01, 02, 03,... horas)
for /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set hora=%%a)
ren "%ruta%\%temporal%" dd%formato%01.T65%hora%%time:~3,2%
goto :eof
:fin
::Eliminamos el fichero auxiliar
DEL .\listado_temporal.txt
)

¡Muchas gracias! 

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas