Comandos Batch en Windows

Archivos por lotes (batch) Los tipos de fichero que puede ejecutar MS-DOS desde línea de comandos deben tener la extensi

Views 306 Downloads 73 File size 695KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Archivos por lotes (batch) Los tipos de fichero que puede ejecutar MS-DOS desde línea de comandos deben tener la extensión .exe, .com o .bat. Los dos primeros son archivos en lenguaje máquina (compilados), el tercero es un fichero ASCII, cuyas líneas son comandos MS-DOS que serán interpretados por la shell. Para llamarlos basta con escribir su nombre en la línea de comandos, no es necesario especificar la extensión, pero deben estar accesibles: bien en el directorio actual ( . ), o bien en alguno de los directorios especificados en la variable PATH. ¿Qué sucede si dos archivos ejecutables se denominan igual?, los ficheros bat son los que tienen menor prioridad de ejecución: 1º) macros 2º) comandos internos 3º) .exe 4º) .com 5º) .bat Ejemplo. El siguiente archivo bat crea una unidad virtual Z: para el directorio en que nos encontramos: uvz.bat subst Z: . C:\Documents and Settings\Administrador>copy con uvz.bat subst Z: . ^Z 1 archivos copiados. C:\Documents and Settings\Administradoruebas>uvz ejecuto el archivo bat C:\Documents and Settings\Administrador>subst Z: . ejecutar C:\Documents and Settings\Administradorebas>z: Z:\>subst Z:\: => C:\Documents and Settings\Administrador Puede contener múltiples líneas: uvz.bat subst /d Z: subst Z: . subst comentarios

me muestra el comando que va a

En un archivo por lotes podemos incluir líneas de comentario con la palabra REM (remark): REM comentario Comando ECHO Nos permite visualizar mensajes en pantalla. ECHO [mensaje | ON | OFF] Muestra mensajes o activa y desactiva el eco del comando. Escriba ECHO sin parámetros para mostrar la configuración actual del eco. echo. inserta una línea en blanco El siguiente bat muestra un listado simple de directorio, separando archivos de directorios: REM list.bat echo --- ARCHIVOS --dir /a-d /b /on echo --- DIRECTORIOS --dir /ad /b /on Eco de los comandos Cada comando de un archivo por lotes es visualizado en pantalla antes de ser ejecutado. Esto puede estar bien para depuración, pero a veces es un poco molesto: La ejecución del fichero bat anterior (list.bat) sería: C:\Documents and Settings\Administrador>list C:\Documents and Settings\Administrador>REM list.bat echo --- ARCHIVOS --- dir /a-d /b /on echo --- DIRECTORIOS --- dir /ad /b /on list --- ARCHIVOS --ntuser.bak ntuser.dat NtUser.dat.LOG ntuser.ini --- DIRECTORIOS --Escritorio Favoritos Menú Inicio Mis documentos Estructura de bifurcación GOTO En un archivo bat la ejecución de los comandos no es necesariamente secuencial, la intrucción GOTO nos permite continuar la ejecución del archivo BAT en otro punto del mismo: GOTO etiqueta -comandos:etiqueta -comandosEl siguiente archivo zzz.bat muestra de manera indefinida los segundos pasar: @echo off set cont=0 :bucle cls echo Mira pasar el tiempo ... %cont% ping -n 1 -w 800 0.0.0.1 > NUL set /a cont=cont+1 goto bucle Para la mayoría de los comandos, cuando no pueden ejecutarse por algún motivo, se muestra el mensaje de error correspondiente y continúa la ejecución con el siguiente de la lista. En el caso del GOTO (y unos pocos más), si no existiera la etiqueta 'bucle' finalizaría el programa con un error.

Su uso principal es en las estructuras if. Pausar el programa A veces interesará suspender temporalmente la ejecución de un archivo bat para que el usuario lleve a cabo alguna acción: encender la impresora, insertar cierto disquete, interrumpir el proceso, ... PAUSE Suspende el proceso de un programa por lotes y por muestra el mensaje Presione una tecla para continuar... Ejemplos: @ECHO OFF CLS ECHO Inserte el diskette de nóminas en la unidad A: PAUSE ... @ECHO Se van a borrar todos los archivos de la unidad Z: @ECHO Ctrl + C para interrumpir @PAUSE ... Carácter de escape en MS-DOS Cuando deseamos permutar el significado de alguno de los caracteres con significado especial (pipe, operadoress de redirección, ...) le precederemos del símbolo ^ (ALT + 94). El siguiente programa BAT no funcionaría como se espera, pues interpreta el pipe como "redirección a entrada estándar del comando /?": ayuda.bat @echo off echo Sintaxis: echo reboot [ hh:mm | /? ] X:\>ayuda Sintaxis: "/?" no se reconoce como un comando interno o externo, programa o archivo por lotes ejecutable. La solución sería: echo reboot [ hh:mm ^| /? ] También sería útil en un caso como el siguiente: echo ^ > pagweb.html

para evitar que la shell interprete cierto símbolos mayor/menor como operadores de redireccionamiento. Paso de parámetros a un archivo bat Hay dos métodos para pasar información: 1) línea de comandos 2) entrada estándar 1- Paso de parámetros a un archivo bat desde entrada estándar SET /P variable=[mensaje] El modificador /P permite establecer el valor de una variable para una línea de entrada escrita por el usuario. Muestra el mensaje antes de leer la línea de entrada. NOTA: Funciona a partir de W2000, y deben estar habilitadas las extensiones de comando. grosero.bat @echo off set /p nombre=¿Cómo te llamas? echo. echo nunca me gustó el nombre de %nombrex% Por recibir el argumento desde entrada estándar, podemos introducir la información a través de de un pipe, o redirigida desde un archivo o dispositivo: X:\pruebas>grosero.bat ¿Cómo te llamas? Paco Pico nunca me gustó el nombre de Paco Pico X:\pruebas>echo Ferreolo Anastasio | grosero.bat ¿Cómo te llamas? nunca me gustó el nombre de Ferreolo Anastasio X:\pruebas>grosero.bat < grosero.bat ¿Cómo te llamas? nunca me gustó el nombre de @echo off NOTA:

Podemos usar comillas en el mensaje que no serán visualizadas: set /p nombre="¿Cómo te llamas? " 2- Paso de parámetros a un archivo bat desde línea de comandos Podemos introducir datos al fichero .bat desde línea de comandos, que serán almacenados en las denominadas variables posicionales: %0, %1, %2, ..., %9

En %0 se almacena el nombre del comando En %1 se guarda el valor del primer argumento

En %2 se guarda el valor del segundo argumento, y así sucesivamente. El parámetro %* contiene la lista con todos los argumentos introducidos desde línea de comandos. El siguiente programa repite lo que introducimos desde línea de comandos (excepto el nombre del comando): repite.bat @echo %* Y sin mucho esfuerzo podemos dar la vuelta a una frase de hasta 9 palabras: reverse.bat @echo %9 %8 %7 %6 %5 %4 %3 %2 %1 X:\>repite lo que yo te diga lo que yo te diga X:\>reverse lo que yo te diga diga te yo que lo SHIFT En el ejemplo anterior, vemos que si la frase tiene más de 9 palabras, reverse no las visualiza: X:\>reverse En un lugar de la mancha cuyo nombre no quiero acordarme nombre cuyo de Mancha la de lugar En Cuando los argumentos desde línea de comandos son más de 9, es necesario irlos desplazando si queremos leer todos. El comando SHIFT desplaza el valor de todos los argumentos posicionales un lugar hacia la izquierda:

modifiquemos un poco el fichero reverse.bat para ver el funcionamiento de shift: reverse.bat @echo off

echo %9 %8 %7 %6 %5 %4 %3 %2 %1 shift echo %9 %8 %7 %6 %5 %4 %3 %2 %1 shift echo %9 %8 %7 %6 %5 %4 %3 %2 %1 X:\> en un lugar de la mancha cuyo nombre no quiero acordarme… nombre cuyo de Mancha la de lugar un En no no nombre cuyo de Mancha la de lugar un quiero quiero no nombre cuyo de Mancha la de lugar Si las extensiones de comando están habilitadas, podemos comenzar los deplazamientos en un determinado parámetro. Por ejemplo: SHIFT /2 Realiza el desplazamiento a partir del argumento %2, dejando fijos los parámetros %0 y %1 Estructura de control: IF Mediante la estructura IF podemos realizar un procesamiento condicional en programas por lotes. IF [NOT] {cadena1==cadena2 | EXIST archivo | ERRORLEVEL número} comando cadena1==cadena2 - La condición es verdadera si las cadenas de texto son exactamente iguales (comparación de cadenas case sensitive). EXIST archivo - Es verdadero si existe el archivo especificado. ERRORLEVEL número - La condición es verdadera si la ejecución del último comando devolvió un código de salida igual o mayor (>=) que el número especificado. comando - es el comando que se ejecutará si se cumple la condición. NOT - Niega la condición: el comando se ejecutará si la condición es falsa. Cuando no estemos muy seguros de que los operandos del IF vayan a contener algún valor, conviene añadir algún delimitador con el fin de evitar comparaciones con un "vacío". Las siguientes líneas provocarán un error cuando el usuario no introduzca ningún valor en la variable posicional %1: IF %1==TE goto TERUEL IF NOT EXIST %1 echo NO ENCUENTRO EL ARCHIVO pues la comparación a realizar sería: IF ==TE goto TERUEL %1 goto FIN :ERROR echo No se encontró el fichero %1 :FIN

¿Qué sucede si %1 es un directorio? ERRORLEVEL Casi todos los comandos, tras su ejecución, devuelven un código de estado, que es un número indicativo de cómo ha finalizado la ejecución del programa. Este código suele ser 0 cuando la ejecución finalizó con éxito, y otro valor si hubo algún tipo de anomalía. Cuando el comando IF compara el errorlevel, nos devolverá 'true' cuando este sea superior o igual al número especificado. Es decir: IF ERRORLEVEL 3 comando equivaldría a: IF NOT ERRORLEVEL 3 comando equivaldría a:

si (errorlevel >= 3) comando si (errorlevel < 3) comando

Los siguientes fragmentos de código tienen el mismo efecto: 1) IF ERRORLEVEL 1 goto ALGUN_ERROR - comandos cuando errorlevel=1 2) IF NOT ERRORLEVEL 1 goto CORRECTO - comandos cuando errorlevel>=1 :CORRECTO - comandos cuando errorlevelNUL 2>NUL if errorlevel 1 goto NO-DISCO REM aquí irían las operaciones a realizar sobre el diskete goto FIN :NO-DISCO echo Introduzca un disquete en la unidad A: pause goto LEER :FIN NOTA: Podríamos haber utilizado DIR, aunque si el directorio raíz está vacío también devuelve un errorlevel igual a 1. ejercicios. 1. El siguiente programa en ensamblador lee una pulsación de teclado y almacena su código ASCII en la variable ERRORLEVEL:

Z:\>debug getch.com No se encuentra el archivo -a 1517:0100 mov ah, 08 - función que captura la pulsación de una tecla sin eco, 1517:0102 int 21 almacena el resultado en AL 1517:0104 mov ah, 4C - función que retorna al programa llamante, con código de 15A6:0106 int 21 retorno el almacenado en AL 15A6:0108 -r cx CX 0008 :8 -w Escribiendo 00008 bytes -q Z:\>getch - aquí pulso la X mayúscula Z:\>echo %errorlevel% 88 Completar el siguiente archivo BAT que muestra un menú con varias opciones: @echo off :MENU cls echo elija opción echo A-Archivo de clientes echo B-Archivo de proveedores echo C-Finalizar getch if errorlevel ..?.. goto CLIENTES, PROVEEDORES o FIN ..?.. if errorlevel ..?.. goto CLIENTES, PROVEEDORES o FIN ..?.. if errorlevel ..?.. ... ..?.. goto MENU :CLIENTES ... :PROVEEDORES ... :FIN Códigos ASCII: A (65), B (66), C (67), a (97), b (98), c (99) 2. Escribir un programa ping2.bat que nos permite hacer un ping a múltiples hosts de una misma red. Nos mostrará un mensaje diciendo si el host está o no conectado:

C:\>ping2 13 2 5 55 99 128 129 130 131 132 133 200 201 222 192.168.1.13 - conectado 192.168.1.2 - conectado 192.168.1.5 - NO ESTÁ CONECTADO 192.168.1.55 - conectado ... INDICACIÓN:

Cuando se hace ping a una IP, el errorlevel devuelto siempre es 0, independientemente de que nos respondan con un pong. Para discernir entre un host conectado y uno inalcanzable, debemos generar un errorlevel, por ejemplo buscando con FIND alguna palabra en la información mostrada por el PING, que será distinta en cada caso. 2. Mejorar el programa anterior, de manera que el primer argumento sea la red: C:\>ping3 10.0.0 13 2 5 55 99 128 129 130 131 132 133 200 201 222 10.0.0.13 - conectado 10.0.0.2 - conectado 10.0.0.5 - NO ESTÁ CONECTADO 10.0.0.55 - conectado ...

MEJORAS en el IF Cuando las extensiones de comando están habilitadas, IF tiene mayor funcionalidad: a) Podemos preguntar por la existencia de variables: IF DEFINED variable comando C:\sirio>set x=25 C:\sirio>if defined x echo Ya existe la variable x, su valor es %x% Ya existe la variable x, su valor es 25 b) Y realizar comparaciones lógicas, diferentes a la igualdad: IF [/I] cadena1 op-log cadena2 comando Los operadores lógicos admitidos son: EQU - igual NEQ - no igual LSS - menor que LEQ - menor que o igual GTR - mayor que GEQ - mayor que o igual /I indica que la comparación se hará case insensitive (ignora la diferencia entre MAYs y mins) c) Ahora el IF admite más de un comando, el grupo de comandos debemos encerrarlo entre paréntesis. También admite la cláusula (opcional) ELSE: IF expr-lógica ( - sentenciaS TRUE ) ELSE (

set a=Andorra C:\>set b=Barcelona C:\>IF a LSS b (echo %a% %b%) ELSE (echo %b% %a%) Andorra Barcelona Expansión retardada de variables Las variables comprendidas entre los paréntesis las expande en el momento de la llegada al IF: antes de ejecutar ninguna de las instrucciones interiores. En el siguiente programa: @echo off set VAR=basura echo antes del IF: %VAR% IF DEFINED VAR ( set VAR=CHATARRA echo en el IF: %VAR% ) echo después del IF: %VAR% su ejecución nos daría un resultado un tanto sorprendente: C:\prueba>prog antes del IF: basura en el IF: basura ¡¡ Pero si ya he cambiado el valor de la variable !! después del IF: CHATARRA La solución a este problema es utilizar lo que en palabras de µsoft se conoce como "expansión de variables retardada" (ver cmd /? y set /?): 1. Debemos habilitarla (por defecto vienen deshabilitadas), para ello necesitamos abrir una subshell: cmd /v:on o bien introducir como primera instrucción del bat: SETLOCAL ENABLEDELAYEDEXPANSION 2. Las variables que deseemos que se expandan en el momento preciso de su utilización las rodearemos con admiraciones (!). El siguiente programa funcionaría correctamente: @echo off set VAR=basura echo antes del IF: %VAR% IF DEFINED VAR ( set VAR=CHATARRA echo en el IF (1): %VAR%

echo en el IF (2): !VAR! ) echo después del IF: %VAR% C:\Documents and Settings\sirio\prueba>cmd /v:on Microsoft Windows 2000 [Versión 5.00.2195] (C) Copyright 1985-2000 Microsoft Corp. C:\Documents and Settings\sirio\prueba>vprog antes del IF: basura en el IF (1): basura repite ms-dos es "bueno, bonito y barato" ms-dos es "bueno, bonito y barato"

NOTA: Si las extensiones de comandos están habilitadas, podemos suprimir las comillas de una variable con el símbolo ~ : for %%X in (%*) do echo %%~X (más información: for /?) ejemplo 2 Cuando aparece un * en la lista, lo interpreta como un comodín, y antes de aplicar el comando se creará una lista de archivos que cumpla con la expresión regular. En la elaboración de la lista sólo utiliza archivos, NO directorios. C:\pruebas>FOR %f IN (*) DO @echo %f for %f in (*.png, *.jpg, *.gif) do move %f C:\Recycled En el último ejemplo hemos movido las imágenes con formatos gráficos de internet a la papelera del disco C:. - Echar un vistazo a la papelera desde Windows ¿se ven? ¿Y desde MS-DOS? - Vaciar la papelera desde Windows. ¿Se han borrado? - Volver al día siguiente y comprobar que las imágenes siguen ahí: aunque tiremos de la cadena 1000 veces, los documentos nunca desaparecerán. Una curiosa forma de esconder documentos y que nadie los borre: en la basura. ejemplo 3 El siguiente archivo BAT nos lista todos los archivos ejecutables (.exe, .com, .bat) del directorio pasado desde línea de comandos. (Si no pasamos argumento, muestra los del raíz) @echo off FOR %%X IN (%1\*.exe %1\*.com %1\*.bat) DO echo %%X

MEJORAS en el FOR Cuando las extensiones de comandos están habilitadas (por defecto lo están, más información: CMD /? ), el comando FOR admite una serie de parámetros que amplían su funcionalidad: FOR /R [ruta] %V IN (lista) DO comando copy con crea.bat @ECHO OFF FOR /L %%A IN (1 1 %1) DO ECHO 2> %2%%A.txt >NUL ^Z 1 archivos copiados. C:\pruebas>crea 5 churro

C:\pruebas>DIR CH* /B churro1.txt churro2.txt churro3.txt churro4.txt churro5.txt El siguiente archivo BAT, hace un ping a broadcast, mostrando sólo la direcciones de aquellos que contestan: C:\pruebas>more > pingred.bat @ECHO OFF SET RED=192.168.1. FOR /L %%H IN (1, 1, 255) DO ping -n 1 %RED%%%H | FIND "TTL=" ^Z C:\pruebas>pingred Respuesta desde 192.168.1.1: bytes=32 tiempo=1ms TTL=128 Respuesta desde 192.168.1.13: bytes=32 tiempofor /F "tokens=1,3,5" %i in (fich.txt) do @echo %i - %j - %k El - y - cerebro, que - llevan - primacía la - son - que coplas - Jorge - a Podemos escoger rangos, en el siguiente ejemplo nos quedamos con las 3 primeras palabras y la 5: X:\>for /F "tokens=1-3,5" %a in (fich.txt) do @echo %a %b %c - %d El corazón y - cerebro, que se llevan - primacía la razón, son - que coplas de Jorge - a Y si deseamos la línea completa a partir de la 7ª palabra: X:\>for /F "tokens=7*" %A in (fich.txt) do @echo %A %B dos grandes vísceras los sentimientos y de el arranque de las muerte de su padre. Y si queremos toda la línea, seleccionaremos todos los tokens de cada línea: X:\>for /F "tokens=*" %m in (fich.txt) do @echo [ %m ] [ El corazón y el cerebro, las dos grandes vísceras ] [ que se llevan la primacía de los sentimientos y de ] [ la razón, son las que presiden el arranque de las ] [ coplas de Jorge Manrique a la muerte de su padre. ] delimitadores En los ejemplos anteriores los "tokens" coincidían con las palabras, pues para separarlos se han utilizado el espacio en blanco y la tabulación. Podemos modificar los delimitadores con la cláusula delims= En el siguiente ejemplo anulamos los delimitadores y obtenemos lo mismo de antes: X:\>for /F "delims=" %K in (fich.txt) do @echo [ %K ] [ El corazón y el cerebro, las dos grandes vísceras ] [ que se llevan la primacía de los sentimientos y de ] [ la razón, son las que presiden el arranque de las ] [ coplas de Jorge Manrique a la muerte de su padre. ] Utilizamos como delimitadores los signos de puntuación (punto, coma, punto y coma, y dos puntos) - no debe haber espacios entre ellos- y nos quedamos con el primer token: X:\>for /F "delims=.,;:" %m in (fich.txt) do @echo %m El corazón y el cerebro que se llevan la primacía de los sentimientos y de la razón

coplas de Jorge Manrique a la muerte de su padre Podemos combinar delimitadores y tokens: for /F "tokens=1,2,3 delims=.,;:" %M in (fich.txt) do @echo %M %N %O Y utilizar otras cláusulas, como skip=nº, que se saltaría las n primeras líneas del archivo, empezando a procesar en la n+1, o eol=carácter, que interpreta las líneas que comienzan por ese carácter como líneas de comentario y no serán procesadas, o useback que cambia la semántica de la lista: (`comando`) , ('cadena') , (archivo) ("archivo1 archivo2 archivo3") B) COMANDO El funcionamiento es similar al de los ficheros, únicamente que tendremos que encerrar el comando con comillas simples: X:\>for /F "tokens=15 delims=: " %x in ('ipconfig ^| find "IP"') do set myIP=%x x:\>set myIP myIP=192.168.1.33 Observar el carácter de escape ^ necesario para que el pipe lo interprete dentro del comando en lugar de ser interpretado para el FOR. C) CADENA Con el siguiente comando añadimos la fecha a un nombre de archivo: X:\>type rdate.bat for /f "tokens=2-4 delims=/ " %%W in ("%date%") do ren %1 %%Y%%X%%W-%1 X:\>rdate backup.bat Ejecuta: ren backup.bat 20060219-backup.bat FORMATOS DE SALIDA Podemos especificar un formato para la variable del for. Por ejemplo: C:\Documents and Settings\sirio>for %x in (*) do @echo %~fsx C:\DOCUME~1\sirio\mueve.bat C:\DOCUME~1\sirio\TEMPFI~1.DIF f: ruta completa s: short name C:\DOCUME~1\sirio\EXCURS~1.TXT C:\DOCUME~1\sirio\EXCURS~2.TXT C:\DOCUME~1\sirio\EXCURS~3.TXT C:\DOCUME~1\sirio\ABC~1.TXT C:\DOCUME~1\sirio\DIAD~1.TXT C:\DOCUME~1\sirio\HID~1 C:\DOCUME~1\sirio\FONTS~1.CAC C:\Documents and Settings\sirio>for %x in (*) do @echo %x mueve.bat tempfile.diff

Excursiones.txt Excursiones del año 2004.txt Excursiones del año 2005.txt A B C.txt dia D.txt .hid .fonts.cache-1 O simplemente %~X, que elimina las comillas (si las tuviera) como vimos arriba. Podemos consultarlos todos ejecutando for /? Acortar direcciones: Cuando usamos un for para recorrer los archivos nos devuelve la dirección entera del archivo. Esto es molesto, cuando lo que queremos es solo su nombre, o saber su ubicación. Ahora les voy a enseñar una técnica para acortar esas direcciones. En el caso por ejemplo de que la variable X tenga la dirección de un archivo y solo quisiéramos saber su extensión, usaríamos: %~Xx y si quisiéramos saber en que unidad se encuentra: %~dX Para entender un poco mejor esto, miremos esto como una sintaxis. Siempre se usara %~ seguido de una letra que representa lo que queremos obtener (el nombre, la extensión, etc) y por ultimo el nombre de la variable. Las letras que podemos usar son: • • • • • • • • •

f Ruta y Nombre d Nombre Unidad donde se encuentra p Solo ruta n Solo nombre x Extensión s Ruta abreviada a Atributos t Fecha y hora de creación z Tamaño del archivo

Por ejemplo, este programa nos mostrara algunos datos de los archivos que existan en la misma carpeta y directorios superiores. @echo off FOR /R %%X in (*) DO ( echo Nombre: %%~nX echo Extension: %%~xX echo Tamaño: %%~zX echo. )

Expansión de variables retardada Cuando aparecen variables de entorno en las estructuras IF y FOR, su valor es calculado al inicio de éstos, y ya no se modifica hasta que finaliza el bucle for o la agrupación de sentencias. El siguiente programa debería contar el número de veces que aparece la palabra %2 en el fichero %1: @echo off set cont=0 for /f "tokens=*" %%L in (%1) do ( for %%P in (%%L) do ( if /I "%%P"=="%2" set /A cont=%cont%+1 ) ) echo En %1 aparece %cont% veces la palabra %2 Pero la ejecución siempre nos da el mismo resultado: Z:\pruebas>cuenta Quijote.txt sancho En Quijote.txt aparece 0 veces la palabra sancho Pues la variable cont se sustituye por su valor (0) al entrar en el bucle y siempre estoy ejecutando la instrucción: if /I "%%P"=="%2" set /A cont=0+1 Por lo que el resultado final del programa será 0 ó 1 (depende de si el último IF de todos es cierto o no) La solución es utilizar una shell con "sustitución de variables retardada", donde las variables que deseemos que se sustituyan en el mismo instante de su utilización las encerraremos con admiraciones. Deberemos cambiar la línea anterior por: if /I "%%P"=="%2" set /A cont=!cont!+1 Y ejecutar el programa en una shell con susitución retardada: cmd /v:on Aunque si deseamos que el programa bat se ejecute por defecto, con sustitución de variables retardada, podemos añadir como primera línea: SETLOCAL ENABLEDELAYEDEXPANSION Subrutinas: Llamar a un fichero BAT desde otro fichero BAT Desde un fichero BAT podemos invocar la ejecución de otro fichero BAT (subrutina) de varias formas:

1: Llamada sin retorno: Escribiendo el nombre de otro archivo bat En este caso el control se transfiere de un programa bat a otro, por finalizada la ejecución del programa bat que realizó la llamada (es como un GOTO sin retorno). Por ejemplo, con los siguientes archivos bat: --- principal.bat @echo off echo INICIO PRINCIPAL set x=PRINCIPAL rutina echo VARIABLE X: %x% echo FIN PRINCIPAL

--- rutina.bat @echo off echo ejecutando el subprograma ... echo variable x: %x% set x=SUBPROGRAMA echo variable x: %x% echo finalizando el subprograma

El resultado de la ejecución sería: Z:\pruebas>principal INICIO PRINCIPAL ejecutando el subprograma ... variable x: PRINCIPAL variable x: SUBPROGRAMA finalizando el subprograma Z:\pruebas>set x x=SUBPROGRAMA

( se han ejecutado en la misma shell )

2: Ejecución en subshell: se abre una subshell donde se ejecutará el subprograma: cmd /c progbat2 Al abrirse una nueva subshell, todas las variables de entorno que defina en la subrutina se pierden al volver a la shell principal. Cuando finaliza la subrutina, se continúa con la ejecución del programa principal. En el programa "principal.bat", cambiamos la línea de llamada por:

cmd /c rutina

El resultado de la ejecución es: Z:\pruebas>principal INICIO PRINCIPAL ejecutando el subprograma ... variable x: PRINCIPAL variable x: SUBPROGRAMA finalizando el subprograma VARIABLE X: PRINCIPAL FIN PRINCIPAL

, – desplazamiento lógico (bit a bit) & – bit a bit y ^ – bit a bit exclusivo o | – bit a bit = *= /= %= += -= – asignación &= ^= |= = , – separador de expresión Si usamos una variable de entorno dentro de una expresión matemática y dicha variable no existe, será asumido que contiene un cero. Veamos los matices de lo anterior, ya que si no tenemos en cuenta algunas matizaciones ya comentadas en este documento habrá expresiones que nos darán error. IMPORTANTE: Volvamos a recordar que hay símbolos especiales que no pueden escribirse directamente, por ejemplo: &, , |, o incluso ^. Cada uno de ellos debe ir precedido por un ^. Es decir, el bit a bit exclusivo ^, debe escribirse como ^^ ya que si no el intérprete de comandos lo interpretará erróneamente. Veamos ejemplos de “asignaciones”. set /a x=x+1 podemos sustituirlo (abreviarlo) por una notación similar al C o C++, es decir: set /a x+=1 (a la variable “x” sumarle 1 y asignárselo a “x”) Lo mismo: set /a x=x-1 es equivalente a: set /a x-=1 set /a x=x*23 es equivalente a: set /a x*=23 etc… para el resto de operaciones matemáticas de asignación citadas anteriormente. Veamos el siguiente problema: ¿qué solución tiene? set /a x=8, y=2, z=16 set /a z-=(x-y)/2+5^ c:\log.txt El símbolo “>” está indicando que todo lo que vaya a salir por el STDOUT se escribirá, en vez de en la consola, en un archivo de texto c:\log.txt. Repito, porque es importante el matiz: STDOUT a fichero de texto. Es decir, si el comando copy no puede copiar, recordemos que el mensaje de error lo saca en STDERR, por tanto en el fichero de texto no se escribiría nada, ya que en el ejemplo anterior, con el símbolo >, sólo se ha redirigido el STDOUT. El STDERR queda con los valores predeterminados por el sistema operativo: es decir, se escribe el mensaje de error en consola. *** Hemos comentado que a voluntad del programador de un comando o programa, este puede terminar correctamente o bien establecer un código de error al finalizar (escriba o no además un mensaje explicativo). El sistema operativo es el encargado de capturar esos códigos de error y los deja a nuestra disposición en una variable de entorno llamada %ERRORLEVEL% Podemos, por ejemplo, verificar cual es el comportamiento del comando “copy”. Para ello vamos a realizar el siguiente ejemplo creándonos una carpeta de trabajo llamada c:\tmp c: cd \ md tmp echo “texto de un fichero” > c:\tmp\fichero.txt Con esto nos hemos posicionado en c: (por si no lo estuviésemos), hemos ido a su carpeta raíz (cd \), y hemos creado una carpeta llamada tmp en donde estuviésemos posicionados en ese momento (md tmp) -md es abreviatura de “makedir”: crear directorio-. La última línea (echo) nos mostraría por pantalla “texto de un fichero”, es decir nos lo mostraría en el STDOUT. Pero con el símbolo “>” lo que hacemos es redirigir el STDOUT (la consola en este caso) a un fichero que en nuestro caso es: c:\tmp\fichero.txt. Si lo abrimos con el cuaderno de notas, veremos realmente el texto anterior. Vamos a copiarlo en otro. Ejecutamos por ejemplo: copy c:\tmp\fichero.txt c:\tmp\copia.txt Si a continuación de este comando ejecutamos: echo %ERRORLEVEL% veremos que el comando anterior nos informa que ha terminado con 0 (se considera normalmente 0 una finalización correcta). Vamos a provocar que el copy termine con error para ver cual es su comportamiento en este caso. Un método muy sencillo seria proteger contra escritura el fichero de salida y luego intentar escribir en él. Es decir: attrib c:\tmp\copia.txt +r (+r es “read only” -sólo lectura-) copy c:\tmp\fichero.txt c:\tmp\copia.txt Vemos que ahora en pantalla nos informa que “Acceso denegado”. Si a continuación ejecutamos: echo %ERRORLEVEL% veremos que el código de retorno es 1. NOTA: en general los mensajes de error deben buscarse en la documentación del programa o

comando ya que son a voluntad del programador. El sistema operativo lo único que hace es situarnos el código de retorno en %ERRORLEVEL% y nosotros podremos tomar acciones en un script de comandos analizando dicha variable de entorno cuando nos interese controlar los códigos de terminación. Bien, lo anterior no ha sido más que un ejemplo para intentar introducir los “redirectores” del sistema operativo. OPERADORES DE REDIRECCIÓN > Escribe la salida del comando (normalmente STDOUT) en un fichero o un dispositivo (puede por tanto redirigirse a otro dispositivo, no sólo a archivo), en lugar de en la ventana del Símbolo del sistema. < Lee la entrada (STDIN) del comando desde un archivo, en lugar de leerla desde la consola. >> Añade la salida del comando al final de un archivo sin eliminar la información que ya está en él. >& Escribe la salida de un controlador en la entrada de otro controlador (lo vemos posteriormente en detalle) & se escribe la salida de un controlador (“handle”) en otro. Vayamos a un ejemplo práctico. En los ejemplos anteriores hemos visto que la salida de un comando como el copy podemos escribirlo en un fichero con el símbolo >. Pero también hemos comentado que sólo redirige en STDOUT, por tanto, si el copy enviase un mensaje de error (STDERR) esto no se vería en el fichero. Esto es un problema si lo que queremos es crear un log de ejecución de un script para poder ver posteriormente la ejecución: los mensajes de error precisamente los habríamos perdido. Pero… recordemos que > escribe el STDOUT. Si fuésemos capaces de “redirigir” el STDERR al STDOUT, entonces el > nos escribiría todos los mensajes, de funcionamiento correcto o erróneo en el fichero. Es decir, si hacemos: copy c:\tmp\fichero.txt c:\tmp\copia.txt >c:\log.txt sólo los mensajes de funcionamiento correcto quedarían en c:\log.txt. Pero en cambio si redirigimos la salida de errores: STDERR (“handle” numero 2) al STDOUT (“handle” numero 1) y luego escribimos, en ese caso todo quedaría reflejado en el archivo log. Por tanto: copy c:\tmp\fichero.txt c:\tmp\copia.txt 2>&1 >c:\log.txt *** Operador de canalización (“|”) o “pipe”. Este es de los más interesantes ya que permite pasar “toda” una salida de datos a un programa que espera “toda” una entrada de datos en flujo. No todos los programas están preparados para admitir este tipo de redirección y debe leerse la documentación de cada uno de ellos al respecto. Tenemos tres programas del sistema operativo “more” (más), “find” (buscar) y “sort” (ordenar) que admiten pipes y que nos pueden servir de ejemplo. Veamos. Un dir /s nos muestra todos los archivos desde donde estemos posicionados incluyendo todos los archivos en subcarpetas. Si ejecutamos: dir c:\ /s veremos que empiezan a pasar pantallas de datos que no somos capaces de leer. Podemos redirigir la salida de este comando al “more”. Realmente el “more” no es nada más que un programa que admite como entrada toda la salida de otro comando y que lleva un contador de líneas para irnos mostrando en pantalla 24 líneas y luego esperar a que pulsemos una tecla. Ejecutemos por ejemplo: dir c:\ /s | more (cualquiera de los comandos anteriores puede abortarse con CTRL-C). Un ejemplo de canalización y redirección: imaginemos que queremos en nuestro disco todos los

archivos con extensión .log y dejar la información en un fichero de salida. dir c:\ /b /s | find /I “.log” > c:\ficheros_log.txt Los parámetros que he puesto, tanto en el comando dir, como en el comando find, siempre podemos verlos ejecutando dir /? y find /? para buscar los que mejor se adapten a lo que queremos. Otro ejemplo: ver en orden “inverso” los ficheros de un directorio: dir /b | sort /REVERSE Los filtros (“pipes”) no sólo admiten canalización. También pueden usarse, como cualquier programa, con comandos de redirección para leer entradas y escribir salidas en archivos. Por ejemplo, imaginemos que tenemos un fichero con nombres y queremos ordenarlo alfabéticamente. Simplemente: sort < lista.txt > listaalf.txt Esto indicaría que la entrada al comando sort viene redirigida desde el fichero lista.txt y que la salida, en vez de dejarla en pantalla, nos la escriba en listaalf.txt. *** Los símbolos de redirección y canalización son potentísimos y a veces, incluso a un programador avezado le pueden causar más de un problema o costarle su correcta interpretación. En ejemplos que iremos viendo a lo largo de estos capítulos quedará más claro el concepto. OPERADORES CONDICIONALES Son los operadores && y el operador || Lo que exista después del operador && se ejecutará “sólo” si la instrucción previa a él -en la misma línea- ha terminado correctamente (código 0). Por contra, si usamos || sólo se ejecutará si la terminación de la instrucción previa termina incorrectamente (código distinto de cero) Por ejemplo: md kkk && echo “finalizado correcta la creación” Sólo veremos el mensaje de aviso si la creación de la carpeta kkk ha sido posible. CONFIGURACIÓN CÓMODA DEL INTÉRPRETE DE COMANDOS Aunque esto no tiene nada que ver con los scripts, podemos fijarnos en que al abrir un intérprete de comandos (cmd.exe) no se pueden realizar funciones de copiar y pegar, lo cual puede sernos incómodo en Windows. La manera de configurar el intérprete de comandos es pinchando con el ratón en la esquina superior izquierda del intérprete de comandos, propiedades, marcamos el casillero de “modalidad de edición rápida”. De esta manera, con el botón izquierdo del ratón ya podremos marcar textos. Una vez marcado, pinchamos botón derecho del ratón y esto nos lo envía al portapapeles (es decir, esta es la acción “copiar” a la que estamos acostumbrados. La acción “pegar”, es simplemente botón derecho (sin haber marcado nada previamente). Lo que tengamos en el portapapeles (lo hayamos llevado mediante la acción anterior, o bien lo hayamos copiado desde cualquier otra ventana Windows) lo pegará en donde esté el cursor. CONCEPTOS EN UN SCRIPT – CONTROL DE FLUJOS Acabamos de ver unos conceptos sobre entorno, comandos, variables, etc., que son básicos para poder realizar un script, pero hasta el momento no hemos visto ninguna instrucción excepto las puestas en los ejemplos previos, ni tampoco hemos visto cómo el shell ejecuta el script y cómo se puede tener control sobre la ejecución. Básicamente un script de comandos, tal y como hemos comentado, no es nada más que escribir en un archivo de texto con extensión .bat o .cmd todas las instrucciones que iríamos haciendo manualmente. Además, dentro del propio script, en función de resultados que vayamos obteniendo se pueden tomar acciones. Recordemos algunas de las instrucciones vistas hasta el momento:

Instrucción: ECHO, su objetivo es mostrar por el STDOUT (normalmente la consola) el literal que exista a continuación. Recordemos que lo primero que hace el intérprete de comandos es “expandir” las instrucciones, es decir, si existe una variable de entorno (delimitada por símbolos %), lo primero que hace es sustituir dicha variable por su contenido. Es decir, si escribimos en un script: echo esto es %var% prueba y la variable de entorno “var” contiene el literal “una”, el intérprete de comandos: 1) Realiza la sustitución de las variables de entorno, por tanto la línea quedaría como: ECHO esto es una prueba 2) A continuación, ejecuta la instrucción: Como ECHO es un comando interno que escribe en el STDOUT lo que hay a continuación, nos mostrará el literal “esto es una prueba”. Es importante la matización anterior ya que la expansión de variables es el primer paso y lo es para todas las instrucciones. Si hubiésemos cometido un error y hubiésemos puesto: ECHA esto es %var% prueba 1) Expandiría la instrucción como: ECHA esta es una prueba 2) Intentaría ejecutar la instrucción. “ECHA” no es el nombre de un comando interno, por tanto buscaría en la carpeta en curso y posteriormente en el PATH un programa (otro script, o un .com, o un .exe, etc… de acuerdo a las reglas vistas anteriormente). Si lo encuentra ejecutará el programa o script “ECHA” y si no lo encuentra nos dirá que sucede un error. NOTA: La sintaxis completa de ECHO es: ECHO literal a escribir ECHO. (un “.” pegado a la instrucción sin separación: escribe una línea en blanco) ECHO ON ECHO OFF Estas dos últimas son instrucciones a ejecutar sólo dentro de un script. Veamos su uso. Nos creamos un script llamado por ejemplo: pr.cmd en mi usuario y en una nueva carpeta de pruebas llamada “tmp” con el contenido: set var=Hola echo %var% mundo. set var= Lo guardamos en disco y ahora lo ejecutamos. ¿Qué vemos?: C:\Documents and Settings\miusuario\tmp>set var=Hola C:\Documents and Settings\miusuario\tmp>echo Hola mundo Hola mundo C:\Documents and Settings\miusuario\tmp>set var= Es decir, nos ha ido mostrando todas las líneas que va ejecutando y mezclado con las salidas que a su vez va dando el script. Si queremos suprimir la salida de las líneas y dejar solamente la salida de los comandos, es decir “Hola mundo”, lo primero que debemos decirle al script es que no queremos “ECO” de lo que va traduciendo. Este “ECO” es útil cuando estamos depurando y probando un script, pero, cuando lo tenemos finalizado y correcto, lo lógico es ver sólo la salida y no línea por línea. En este caso podemos poner como primera línea del script: @ECHO OFF El símbolo @ como primer carácter en una línea del script indica que no queremos que esa línea se “vea” en la ejecución. Si además le damos la orden ECHO OFF, le estamos diciendo que hasta el final del script, o bien hasta que se encuentre otra orden ECHO ON, no muestre nada de la ejecución (sí de la salida de instrucciones) por pantalla. Es decir, en nuestro caso, si no queremos ver nada más que el literal “Hola mundo”, nos quedan

dos posibilidades: 1) Poner una @ al comienzo de cada instrucción en el script. O bien: 2) Poner como primera línea del script @ECHO OFF Vamos a hacer un paréntesis en este capítulo e introducir el concepto de nombre lógico de dispositivo. NOMBRES LÓGICOS DE DISPOSITIVOS Hay ciertos dispositivos que podemos usar en cualquier comando o dentro de un script con nombres reservados que se refieren a dispositivos, normalmente lógicos, de nuestra máquina. Por ejemplo: CON se refiere a la consola. Lo que se envíe o reciba desde la consola se puede referenciar con CON. LPT1 se refiere a la impresora. Lo que se envíe a él se escribirá en la impresora (si está asignada a ese puerto). NUL dispositivo nulo. Lo que se envíe a él, se pierde. Aunque existen más dispositivos lógicos, llegado este punto sólo vamos a ver estos tres. Veamos unos ejemplos: 1) Imaginemos que hemos recibido una clave de registro de un producto por mail, y lo queremos guardar en un fichero llamado licencia.txt en una carpeta determinada. La manera clásica de hacerlo mediante Windows es abrir el cuaderno de notas, copiar la clave desde el mail recibido y guardar el fichero en la carpeta que queremos con el nombre licencia.txt. Bien, podríamos hacer en una consola de comandos: copy con licencia.txt En este punto se quedará el cursor esperando una entrada. Tecleamos la clave recibida (o la copiamos desde el mail), y para finalizar la entrada de datos le damos a CTRL-Z (CTRL-Z es la marca estándar de fin de fichero). Es decir, hemos copiado desde la consola a un fichero de la misma forma que si hubiésemos copiado un fichero a otro fichero. 2) Queremos enviar un fichero a impresora: copy fichero.txt lpt1 3) No queremos ver, por ejemplo después de un comando copy la línea de “xx archivos copiados” que siempre nos informa el copy. Simplemente redirigimos la salida al dispositivo nulo. copy fichero1.txt fichero2.txt >nul RETOMANDO EL CONTROL DE FLUJOS DE EJECUCIÓN Una vez hecho el paréntesis anterior, vamos a ver las instrucciones de control flujo. Básicamente son 3. 1) Instrucción GOTO (ir a) Permite en un punto determinado de nuestro script “saltar” a otro punto del script. Normalmente se usa después de una pregunta lógica por algún resultado (por ejemplo, dentro de una instrucción IF). GOTO nombre_etiqueta Y en algún lugar de nuestro script debemos tener :nombre_etiqueta (nótense los “:”) En este caso, al ejecutar la instrucción GOTO, buscará en el script la línea :nombre_etiqueta y bifurcará a dicha línea. NOTA: Existe una etiqueta implícita en cualquier script que no es necesario definir, :EOF (End Of File – Fin de fichero). Por tanto, la ejecución de la instrucción GOTO :EOF implica que se saltará hasta el final del fichero y por tanto finalizará el script. 2) Instrucción IF (si). Recordemos que lo encerrado entre corchetes es opcional if [not] errorlevel número comando [else expresión] Estamos verificando si la variable %ERRORLEVEL%, que indica el código de retorno de un comando anterior, tiene un valor determinado. Si lo tiene ejecutará el “comando” y si no lo

tuviese y hemos codificado en la línea (es opcional) un ELSE (en otro caso), ejecutará precisamente ese ELSE. if [not] cadena1==cadena2 comando [else expresión] cadena1 y cadena2 pueden ser cualquier cosa incluidas variables de entorno. Recordemos que lo primero que se hace es la expansión de variables. Hay que tener muchísimo cuidado con esto y no me gustan las instrucciones del estilo anterior a menos que tengamos delimitadores específicos. Voy a intentar explicarlo. Imaginemos que tenemos una variable “var1″ con contenido “1″ y otra “var2″ con contenido también “1″. La instrucción: if %var1%==%var2% echo “valen lo mismo” Se ejecutará sin problemas y nos sacará el mensaje “valen lo mismo”. Si “var2″ contiene un “2″, la instrucción anterior, al no ser iguales, no mostrará nada. Pero… ¿y si “var1″ contiene “Hola mundo”, que sucedería? Pues un desastre. Al expandir la expresión quedaría: if Hola mundo==2 echo “valen lo mismo” Detrás del hola no hay símbolo de comparación, por lo cual la instrucción es sintácticamente incorrecta. Lo mismo pasaría si “var1″ o “var2″ no tienen contenido. En estos casos, el truco consiste en encerrarlas entre algún delimitador. Por ejemplo, comillas -ya que estas definen un literal. Es decir: if “%var1%”==”%var2%” echo “valen lo mismo” Esto al expandirse quedaría: if “hola mundo”==”2″ echo “valen lo mismo” La comparación se realiza entre literales entrecomillados lo cual no provoca error ni aun en el caso de que alguno sea nulo al no tener contenido. if [not] exist nombreDeArchivo comando [else expresión] if [/i] cadena1 operadorDeComparación cadena2 comando [else expresión] El /i realiza la comparación de tal manera que no se distingue entre mayúsculas y minúsculas. Es decir “HOLA” es lo mismo que “hOLa”. Fijémonos que hemos puesto no un == (igualdad) en este caos, sino que por primera vez se ha puesto “operadorDeComparacion”. Este operador que veremos a continuación, y el símbolo == no es nada más que uno de ellos. if defined variable comando [else expresión] OPERADORES DE COMPARACIÓN Especifica un operador de comparación de tres letras. En la siguiente tabla puede ver los valores de operadorDeComparación. EQU igual a (es lo mismo que ==) NEQ no es igual a LSS menor que LEQ menor que o igual a GTR mayor que GEQ mayor que o igual a PARÁMETROS Cualquier script es capaz de recibir parámetros desde la línea invocante. Se considera parámetro cualquier literal enviado en la línea que invoca al script. El sistema considera que los parámetros están separados por espacios en blanco o bien por el delimitador “;”. Cada parámetro se referencia dentro del script por %1, %2, %3, etc… Vamos a crear un script que reciba dos parámetros, el nombre de un fichero y el nombre de una carpeta. El objetivo del script es copiar el archivo desde la carpeta en donde estemos posicionados en la carpeta destino, siempre y cuando no exista ya en el destino. Una manera grosera de realizar el script, llamémosle copia.cmd, sin verificar que los parámetros son correctos, sería:

@echo off if not exist %2\%1 copy %2 %1 Si invocásemos al script de la siguiente manera: copia.cmd mifichero.txt c:\backup al desarrollar la instrucción el script, realizaría: if not exist c:\backup\mifichero.txt copy mifichero.txt c:\backup lo cual es precisamente lo que queríamos hacer. He comentado que este script, tal y como está, está realizado de una manera grosera. Si el nombre del archivo o el nombre de la carpeta destino tuviese espacios en blanco el sistema consideraría que dicho espacio en blanco es un delimitador de parámetros y por tanto nos llegarían al script más parámetros de los deseados. Realmente para realizar correctamente el script deberíamos hacer: @echo off if {%1}=={} goto error if {%2}=={} goto error if {%3} NEQ {} goto error if not exist %1 goto error1 if not exist %2\nul goto error2 if exist %2\%1 goto aviso copy %1 %2\%1 2>&1 >nul if not errorlevel 1 goto correcto echo Copia errónea. Verifique permisos de la carpeta destino. goto:EOF :error echo parámetros erróneos. Deben recibirse dos parámetros. goto :EOF :error1 echo Nombre del fichero origen no existe. goto :EOF :error2 echo Carpeta destino no existe. goto :EOF :aviso: echo El archivo ya existe en el destino. No se ha realizado copia. goto :EOF :correcto echo Archivo copiado correctamente. goto :EOF Y la manera de invocar al comando sería: copia.cmd “nombre fichero.xxx” “c:\carpeta destino” Nótese que hemos entrecomillado cada uno de los parámetros. De esta manera sólo se recibirán dos parámetros ya que si no, se recibirían 4 al usar como delimitador el sistema los espacios en blanco entre ellos. Comentemos un poco el script. * Verificamos que hemos recibido 2 parámetros y sólo 2. * Verificamos que exista el fichero origen * Verificamos que exista la carpeta destino. Para verificarlo usamos un pequeño truco: preguntar por el dispositivo “nul” en la carpeta destino. Si no existe, es que la carpeta no existe. * Verificamos que de acuerdo a las especificaciones del script no exista ya el fichero en la carpeta destino. * Realizamos la copia. Redirigimos todo a nul para que no de mensajes de archivos copiados.

* Comprobamos el código de retorno y si no es cero enviamos el mensaje correspondiente. * Damos un mensaje de copia correcta cuando se ha finalizado correctamente el script. Bien, el ejemplo anterior nos puede servir para la introducción de lo que son los parámetros y cómo se deben usar o referenciar en el script. Vamos a ver toda la casuística más en detalle. Realmente podemos referenciar los parámetros desde %0 a %9. El parámetro recibido en %0 no se teclea y siempre el sistema nos pasa como contenido el nombre del script invocado. Hagamos una prueba: @echo off echo Parámetro 0: %0 %1 a %9 son los posibles parámetros enviados en la línea de comandos. Realmente pueden pasarse más de 9 parámetros pero sólo 9 de ellos serán accesibles directamente. Si pasásemos más, hay que usar el comando shift, el cual tiene por objeto desplazar los parámetros. Es decir, al ejecutar shift lo que se hace es que el %2 pasa a ser %1 (el %1 se pierde por lo que debemos guardarlo), el %3 pasa a ser el %2, etc… De tal manera que al final el %9 pasa a contener el posible décimo parámetro pasado. Realicemos como prueba: @echo off echo Antes de desplazar echo Parametro 1: %1 echo Parametro 2: %2 echo Parametro 3: %3 echo Parametro 4: %4 echo Parametro 5: %5 echo Parametro 6: %6 echo Parametro 7: %7 echo Parametro 8: %8 echo Parametro 9: %9 shift echo Despues de desplazar echo Parametro 1: %1 echo Parametro 2: %2 echo Parametro 3: %3 echo Parametro 4: %4 echo Parametro 5: %5 echo Parametro 6: %6 echo Parametro 7: %7 echo Parametro 8: %8 echo Parametro 9: %9 shift echo Despues de desplazar de nuevo echo Parametro 1: %1 echo Parametro 2: %2 echo Parametro 3: %3 echo Parametro 4: %4 echo Parametro 5: %5 echo Parametro 6: %6 echo Parametro 7: %7 echo Parametro 8: %8 echo Parametro 9: %9 e invoquemos al script anterior (parm.cmd, por ejemplo) de la siguiente manera: parm.cmd 1 2 3 4 5 6 7 8 9 10 11

NOTA: Podemos referenciar “toda” la línea de parámetros mediante %* Si reescribimos el bat anterior: @echo off echo Toda la línea de parámetros es: %* y ejecutamos parm.cmd 1 2 3 4 5 6 7 8 9 10 podemos comprobar la salida. Esto puede ser útil si luego queremos tratar todo como una sola línea y usamos comandos específicos, que veremos más adelante, para tratar dicha línea. A los parámetros y sólo a los parámetros, pueden anteponérseles modificadores los cuales realizan una conversión especifica. Vamos a ver un ejemplo y a continuación daremos todas las posibilidades. Hagamos un script (parm.cmd): @echo off echo Parámetro 1 expandido: %~f1 echo Parámetro 2 expandido: %~f2 Supongamos que nuestro script esté en la carpeta: C:\Documents and Settings\miusuario\tmp> Al ejecutar: parm.cmd aaa.www bbb nos devolverá: Parámetro 1 expandido: C:\Documents and Settings\miusuario\tmp\aaa.www Parámetro 2 expandido: C:\Documents and Settings\miusuario\tmp\bbb Es decir, el delimitador %~f por delante del numero de parámetro nos expande el parámetro considerándolo como si fuese nombre de archivo (sin verificarlo) al nombre completo de unidad, ruta y archivo en donde se esté ejecutando el script. Realmente todos los modificadores posibles de parámetros son los que se describen a continuación: %~1 Expande %1 y quita todas las comillas (“”). %~f1 Expande %1 y lo convierte en un nombre de ruta de acceso completo. %~d1 Expande %1 a una letra de unidad. %~p1 Expande %1 a una ruta de acceso. %~n1 Expande %1 a un nombre de archivo. %~x1 Expande %1 a una extensión de archivo. %~s1 Ruta de acceso expandida que únicamente contiene nombres cortos. %~a1 Expande %1 a atributos de archivo. %~t1 Expande %1 a una fecha/hora de archivo. %~z1 Expande %1 a un tamaño de archivo. %~$PATH:1 Busca los directorios enumerados en la variable de entorno PATH y expande %1 al nombre completo del primer directorio encontrado. Si el nombre de la variable de entorno no está definido o la búsqueda no encuentra el archivo, este modificador se expande a la cadena vacía. La tabla siguiente enumera las combinaciones posibles de modificadores y calificadores que puede usar para obtener resultados compuestos. %~dp1 Expande %1 a una letra de unidad y una ruta de acceso. %~nx1 Expande %1 a un nombre y extensión de archivo. %~dp$PATH:1 Busca los directorios enumerados en la variable de entorno PATH para %1 y expande a la letra de unidad y ruta de acceso del primer directorio encontrado. %~ftza1 Expande %1 a una línea de salida similar a dir. NOTA: En los ejemplos anteriores, se puede reemplazar %1 y PATH con otros valores de parámetros de proceso por lotes. No se pueden manipular parámetros de proceso en los scripts de la misma manera en que se manipulan variables de entorno (funciones de manejo de cadenas vistas anteriormente). No se pueden buscar y reemplazar valores ni examinar subcadenas. Sin embargo, se puede asignar el

parámetro a una variable de entorno para, después, manipular la variable de entorno. Aunque no es necesario memorizarlos sí que es importe saber que existen, ya que algunas veces nos puede ser necesario usarlos para expansión sobre todo en nombres de archivos. INVOCACIÓN A PROCEDIMIENTOS. INSTRUCCIÓN CALL Muchas veces es necesario desde un script llamar a otro procedimiento, o llamar a una subrutina del mismo procedimiento. Vemos ambos casos. * Llamada a procedimiento externo. Vamos a crearnos dos script. El primero de ellos lo llamaremos principal.cmd y con el contenido: @echo off echo estoy en el principal call invocado.cmd echo de vuelta en el principal Y un segundo procedimiento llamado invocado.cmd: @echo off echo estoy en el invocado Si lo ejecutamos veremos los resultados. Recordemos que tanto el procedimiento principal como el invocado pueden recibir parámetros y podemos jugar con ellos como queramos. Por ejemplo: principal.cmd: @echo off echo estoy en el principal echo mi primer parámetro: %1 echo mi segundo parámetro: %2 call invocado.cmd %2 echo de vuelta en el principal invocado.cmd: @echo off echo estoy en el invocado echo el parámetro del invocado es: %1 y ahora lo ejecutamos como principal.cmd primero segundo ¿Qué es lo que vemos?… Nótese, que el ejemplo anterior, si en vez de llamar con CALL, hubiésemos omitido dicho CALL, es decir la línea: CALL invocado.cmd sólo tuviese: invocado.cmd también se ejecutaría el invocado. Pero cuando este terminase, terminaría todo y no volvería al script principal. * Llamada a procedimiento interno (subrutina). La sintaxis es “CALL :nombre”, en donde :nombre es un nombre de etiqueta interno al cual saltará la ejecución del script, pero a diferencia del goto, cuando finalice la propia rutina continuará la ejecución después del CALL invocante. Se considera la finalización de la subrutina cuando se alcanza el fin del archivo por lotes. Pongamos un ejemplo (script.cmd) @echo off echo Parámetro 1: %1 echo Parámetro 2: %2 call :rutina1 %2 echo estoy de nuevo en el principal call :rutina1 %1 echo estoy de nuevo en el principal call :rutina2 parametrosjuntos%1%2

goto final :rutina1 echo en la rutina recibo parámetro: %1 goto:EOF :final echo estoy ya al final Fijémonos que la subrutina la terminamos con goto :EOF. Esto indica que cuando se la invoca con CALL volverá a la línea de continuación del invocante (realmente salta a fin de fichero, con lo que provoca la condición de vuelta que hemos citado anteriormente). CONSIDERACIONES SOBRE ÁMBITO DE VARIABLES Hemos comentado anteriormente que cada programa tiene su área de entorno la cual es una copia del área de entorno del programa invocante, y que por tanto, si se modifican o añaden variables de entorno, esto *sólo* afecta a dicho programa (y por supuesto a los que él invoque, ya que heredarán su entorno). Pero ¿cuál es el entorno de un script? Un script no es en sí un programa: es una secuencia de comandos dentro del shell. Dentro del cmd.exe. Pero además dentro “sólo” del cmd.exe que lo ha invocado. Un script no tiene entorno propio: se usa, y por tanto se modifica o se añaden variables al entorno del cmd.exe invocante (y sólo a él, es decir si tenemos arrancado o arrancamos posteriormente otro cmd.exe, este último no se verá afectado). Si un script llama a otro script (mediante CALL) tendrá acceso a todas las variables modificadas en el script principal. No es conveniente modificar el entorno del cmd.exe (aunque sea el invocante del script), y lo ideal sería que el script, al finalizar, dejase el entorno tal y como estaba antes de arrancarse. Pongamos un ejemplo: un simple script que haga: @echo off set a=%1 set computername=%a%_mio …. Esto es válido y hemos usado una variable llamada “computername” simplemente porque se nos ha ocurrido en el script. Pero, curiosamente, ese nombre de variable ya existía en el sistema (en el entorno del cmd.exe). Por tanto, lo que sucede es que al finalizar el script, ese cmd.exe -y sólo esese quedará en su entorno con una variable que ya existía modificada por el script, y además con otra variable “a” que antes de empezar el script no tenía valor. Lo ideal sería no usar nombres que ya existan en el entorno en el propio script, y además que el script limpiase sus variables internas antes de finalizar. Esto es engorroso y normalmente difícil de controlar. El sistema nos da la posibilidad de hacerlo él automáticamente mediante las instrucciones “setlocal” y “endlocal”. Por ejemplo, si en el script anterior hubiésemos hecho: @echo off setlocal set a=%1 set computername=%a%_mio …… endlocal Es decir, le estamos diciendo desde la instrucción “setlocal” que todo lo que hagamos será local al script. Y cuando se ejecuta “endlocal” (al final del script) le estamos diciendo que deshaga todas las variables usadas y permanezca tal y como estaba desde que se ejecutó la anterior instrucción “setlocal”. Como norma es conveniente en los scripts (o al menos en el principal si usásemos llamadas CALL - esto dependerá de la lógica-) el usar un “setlocal” al inicio del script y un “endlocal” como última instrucción del script. La instrucción “setlocal” admite además opcionalmente la siguiente sintaxis:

setlocal {enableextension | disableextensions} {enabledelayedexpansion | disabledelayedexpansion} Algunas de ellas -las dos últimas- ya las hemos comentado: por defecto el intérprete de comandos tiene desactivada la expansión diferida (a menos que se haya arrancado con /V:ON o bien se hayan modificado ciertas claves de registro para cambiar el comportamiento general del intérprete de comandos), y por ello hay que prestar especial atención a la expansión de las variables de entorno en la línea de comando antes de que esta pase a ejecución (recordemos la sintaxis con “!” como delimitador de la variable de entorno en vez de usar el delimitador “%” normal. Es conveniente revisar ese capítulo ya que el concepto es extremadamente importante). Las dos primeras: {enableextension | disableextensions} no es conveniente tocarlas ya que se desactivarían las extensiones de comandos y las instrucciones: DEL o ERASE COLOR CD o CHDIR MD o MKDIR PROMPT PUSHD PUSHD POPD SET SETLOCAL ENDLOCAL IF FOR CALL SHIFT GOTO START (también incluye cambios en la invocación de comandos externos) ASSOC FTYPE Tendría un comportamiento diferente. Podemos ver estas modificaciones pidiendo la ayuda de cualquiera de las instrucciones anteriores, por ejemplo CALL /? Por defecto, tal y como viene Windows, el valor es: setlocal enableextension disabledelayedexpansion Debido a que es posible que el sistema en donde se vayan a ejecutar nuestros scripts pueda haberse modificado el comportamiento global, siempre es conveniente forzar en nuestro script principal lo que deseamos. Mi consejo además es permitir la expansión diferida del entorno, por tanto, es conveniente siempre poner al comienzo del script principal la instrucción: setlocal enableextension enabledelayedexpansion con lo cual ya podremos usar el delimitador “!” cuando nos interese. COMANDOS INTERNOS DEL INTÉRPRETE DE COMANDOS Llegado a este punto ya podemos ver todos los comandos internos que tiene el intérprete de comandos. Recordemos igualmente que hay una lista alfabética y detallada en el fichero de ayuda ntcmds.chm que reside en \windows\help. Es conveniente para los que se vayan a dedicar a la escritura de scripts el tener un acceso directo en Windows a dicho archivo. En esa lista alfabética figuran tanto los comandos internos de Windows como los externos que nos da la propia versión del sistema operativo. Vamos a dar un repaso de todas formas y un pequeño comentario a cada uno de ellos, excepto para el comando más potente de Windows: el comando FOR, el cual

merecerá todo un capítulo aparte. Es conveniente llegado a este punto que se vaya consultando cada uno de los comandos que citaré a continuación en ntcmds.chm. Los comandos internos son: ASSOC Ver / cambiar asociación a la extensión de un archivo. CALL Llamada a procedimiento. CD o CHDIR Cambiar carpeta en curso. CLS Borrar pantalla. COLOR Atributos de color en el texto enviado a consola. COPY Copiar archivos. DEL o ERASE Borrar archivos. DIR Listar contenido de la carpeta en curso. ECHO Mostrar por pantalla (en STDOUT). ENDLOCAL Fin de tratamiento de variables locales de entorno. EXIT Final de la secuencia de comandos por lotes o sale de un cmd.exe si se invoca directamente. FOR (lo veremos en todo un capítulo aparte). FTYPE Muestra o modifica los tipos de archivos empleados en asociaciones de extensiones de archivo. GOTO Ir a. (Salto incondicional a una etiqueta del script en curso). IF Instrucción de comparación. MD o MKDIR Crear una carpeta. PATH Como instrucción devuelve el contenido de la variable %PATH%. PAUSE Detiene la ejecución de un script y espera a que se pulse una tecla para continuar. POPD Cambia el directorio actual al que se haya almacenado con PUSHD. PROMPT Cambia el símbolo de sistema de Cmd.exe. PUSHD Guarda el nombre del directorio actual para que lo use el comando POPD. REM Es un comentario en un script. Lo que va a continuación no se ejecuta. REN o RENAME Renombra un archivo o una carpeta. RM o RMDIR Borrar una carpeta. SET Asignación de contenido a variables de entorno. SETLOCAL Tratamiento o comportamiento de las variables en un script y de las extensiones de comandos. SHIFT Desplazamiento de los parámetros con que se invoca a un script. START Inicia una ventana independiente de símbolo del sistema para ejecutar un programa o un comando especificado. TYPE Vuelca el contenido de un archivo al STDOUT. VER Muestra el número de versión de Windows. COMANDO ‘FOR’ Es el comando más importante y más potente que podemos usar en un script. Por tanto, vamos a verlo en detalle y haciendo hincapié en ejemplos de su uso. NOTA: Es el único comando que tiene sintaxis diferente ejecutado desde la línea de comandos y ejecutado desde un script. Los subíndices del comando -tal y como se verán a continuación- se expresan con un símbolo % desde la línea de comandos, pero en un script deben expresarse con un doble símbolo, es decir con %%. Definición: Ejecuta un comando especificado para cada archivo de un conjunto de archivos. Sintaxis. Admite varias formas: (recordando que en script %variable debe ser %%variable) 1) for %variable in (grupo) do comando %variable Requerido. Representa un parámetro reemplazable. Utilice %variable para ejecutar for en el símbolo del sistema. Utilice %%variable para ejecutar el comando for dentro de un archivo por

lotes. Las variables distinguen entre mayúsculas y minúsculas y se deben representar con un valor alfabético, como %A, %B o %C. (grupo) Requerido. Especifica uno o varios archivos, directorios, intervalo de valores o cadenas de texto que se desea procesar con el comando especificado. Los paréntesis son obligatorios. El parámetro grupo puede representar un único grupo de archivos o varios. Puede utilizar caracteres comodín (es decir, * y ?) para especificar un grupo de archivos. Los siguientes son grupos de archivos válidos: (*.doc) (*.doc *.txt *.me) (ene*.doc ene*.rpt feb*.doc feb*.rpt) (ar??1991.* ap??1991.*) por ejemplo, desde la línea de comandos: for %f in (c:\windows\*.*) do @echo %f o bien desde un script: for %%f in (c:\windows\*.*) do @echo %%f nos mostrará los archivos que están dentro de la carpeta c:\windows (similar a un “dir” pero sólo nos mostrará el nombre. Ejercicio [for-1]: usando el comando for en la forma citada anteriormente obtener únicamente el nombre del archivo. Si lo ejecutamos vemos que la salida es c:\windows\fichero.ccc, c:\windows\fichero2.xxx, etc., y lo que queremos es únicamente el nombre y extensión del archivo. Evidentemente una manera simple de hacerlo sería: c: cd \windows for %f int (*.*) do @echo %f Pero esto no es lo que se solicita, sino que, con una sola línea for y sin estar posicionado en la carpeta de Windows, se obtenga el mismo resultado que con las tres instrucciones anteriores. (la respuesta a estos ejercicios al final del capítulo). comando Requerido. Especifica el comando que desea ejecutar en cada archivo, directorio, intervalo de valores o cadena de texto incluido en el (grupo) especificado. NOTA: Hay que prestar especial atención al posible uso del %variable dentro de la acción ‘do’ así como al posible uso de variables dentro de él. Recordemos la parte vista anteriormente de expansión diferida o no del comando a la hora de traducir la línea. NOTA: Cuando están habilitadas las extensiones de comandos (es el valor por defecto del cmd.exe en Windows) -ver capítulos anteriores- es posible también las sintaxis que veremos a continuación 2) for /D %variable in (grupo) do comando /D -> Sólo directorios Si grupo contiene caracteres comodín (* y ?), el comando especificado se ejecuta para cada directorio (en lugar de un grupo de archivos de un directorio especificado) que coincida con grupo. La sintaxis es: for /D %variable in (grupo) do comando [opcionesDeLíneaDeComandos] Por ejemplo, para recorrer todas las subcarpetas de la carpeta Windows: for /d %s in (c:\windows\*.*) do @echo %s 3) for /R [unidad :]rutaDeAcceso] %variable in (grupo) do comando

[opcionesDeLíneaDeComandos] /R -> Recursividad. Recorre el árbol de directorios con raíz en [unidad:]rutaDeAcceso y ejecuta la instrucción for en cada directorio del árbol. Si no se especifica un directorio después de /R, se considera el directorio actual. Si grupo tiene únicamente un punto (.) sólo se enumerará el árbol de directorios. Ejercicio [for-2]: Se desea obtener en un fichero llamado c:\datos.txt todos los archivos, un delimitador como puede ser “;” y el nombre de la carpeta en la cual residan. Es decir un archivo de texto con el formato: notepad.exe;c:\Windows … etc… Ejercicio [for-3]: Obtener los mismos datos que en el ejercicio anterior pero recibiendo la carpeta origen por parámetro. 4) for /L %variable in (númeroInicial,númeroPaso,númeroFinal) do comando /L -> Iteración de un intervalo de valores. Se utiliza una variable iterativa para establecer el valor inicial (númeroInicial) y, después, recorrer un intervalo de valores especificado hasta que el valor sobrepase el valor final (númeroFinal) especificado. /L ejecutará la iteración mediante la comparación de númeroInicial con númeroFinal. Si númeroInicial es menor que númeroFinal, el comando se ejecutará. Si la variable iterativa sobrepasa el valor de númeroFinal, el shell de comandos sale del bucle. También se puede utilizar un valor númeroPaso negativo para recorrer un intervalo de valores decrecientes. Por ejemplo, (1,1,5) genera la secuencia 1 2 3 4 5 y (5,-1,1) genera la secuencia (5 4 3 2 1) for /l %i in (5,-1,1) do @echo %i Ejercicio [for-4]: Dar un barrido de ping a las primeras 30 ip’s desde 172.16.0.1 5) Interacción y análisis de archivos. Es la parte más potente del FOR ya que permite ejecución interna de comandos dentro del propio “do” -realiza o puede realizar “spawn” del posible comando dentro del doLo veremos después de entender la solución a los ejercicios. RESPUESTAS A LOS EJERCICIOS (1) [for-1] for %f in (c:\windows\*.*) do @echo %~nxf Revisar el capítulo de “parámetros” para ver los prefijos ~n o bien ~x que pueden ponerse a parámetros (o bien a variables explícitas o implícitas en un for -son equivalentes a parámetros-) para entender el comando anterior. [for-2] Vamos a realizarlo en un script. @echo off setlocal enabledelayedexpansion set ruta= del c:\datos.txt 2>&1 >nul for /r c:\windows %%a in (.) do ( set ruta=%%a&@for %%f in (“!ruta:\.=!\*.*”) do echo %%~nxf;!ruta:\.=! >>c:\datos.txt ) endlocal Razonar el script y cada detalle dentro del for. [for-3]

Vamos a realizarlo en un script. @echo off setlocal enabledelayedexpansion if “%*” EQU “” goto error0 pushd cd “%*” >nul if errorlevel 1 goto error1 set ruta= del c:\datos.txt 2>&1 >nul for /r “%*” %%a in (.) do ( set ruta=%%a&set r=!ruta:\.=!&@for %%f in (“!r!\*.*”) do echo %%~nxf;!r! >>c:\datos.txt ) goto FIN :error0 echo Falta parametro. goto FIN :error1 echo Carpeta recibida por parametro inexistente goto FIN :FIN endlocal popd Razonar el script y cada detalle del uso del parámetro así como los controles realizados. [for-4] for %i in (1,1,30) ping 172.16.0.%i COMANDO ‘FOR’ INTERACCIÓN Y ANÁLISIS DE ARCHIVOS Hemos dejado aparte la interacción y análisis de archivos debido a que es la más compleja y a la vez la que más potencia da a los scripts y que usaremos en muchos de nuestros procedimientos. Es la parte más potente del FOR ya que permite ejecución interna de comandos dentro del propio “do” -realiza o puede realizar “spawn” del posible comando dentro del in-. Vamos a ver la definición formal y la sintaxis, pero sobre todo, a continuación, vamos a insistir en la comprensión real de su ejecución mediante ejemplos. Aconsejo una lectura rápida hasta la parte de “Ejemplos y comprensión del comando”. Definición formal: El análisis de archivos se compone de la lectura de la información de salida, la cadena o el contenido del archivo, su división en líneas individuales de texto y el análisis de cada línea en cero o más testigos. Después, se llama al bucle for con la variable de iteración establecida al valor del testigo. De forma predeterminada, /F pasa el primer testigo separado por espacios en blanco de cada línea de cada archivo. Las líneas en blanco se omiten. Las distintas sintaxis son: Sintaxis: for /F ["palabrasClaveDeAnálisis"] {%% | %}variable in (grupoNombreArchivos) do comando [opcionesDeLíneaDeComandos] for /F ["palabrasClaveDeAnálisis"] {%% | %}variable in (“cadenaLiteral”) do comando [opcionesDeLíneaDeComandos] for /F ["palabrasClaveDeAnálisis"] {%% | %}variable in (‘comando’) do comando [opcionesDeLíneaDeComandos] El argumento grupoNombreArchivos especifica uno o varios nombres de archivo. Cada archivo se abre, lee y procesa antes de pasar al siguiente archivo en grupoNombreArchivos. Para suplantar el comportamiento predeterminado del análisis, especifique “palabrasClaveDeAnálisis”. Se trata de

una cadena incluida entre comillas que contiene una o varias palabras clave que especifican diferentes opciones de análisis. Si incluye la opción usebackq, utilice una de las sintaxis siguientes: for /F ["usebackqpalabrasClaveDeAnálisis"] {%% | %}variable in (“grupoNombreArchivos”) do comando [opcionesDeLíneaDeComandos] for /F ["usebackqpalabrasClaveDeAnálisis"] {%% | %}variable in (‘cadenaLiteral’) do comando [opcionesDeLíneaDeComandos] for /F ["usebackqpalabrasClaveDeAnálisis"] {%% | %}variable in (`comando`) do comando [opcionesDeLíneaDeComandos] En la tabla siguiente se enumeran las palabras clave de análisis que se pueden utilizar para palabrasClaveDeAnálisis. Palabra clave Descripción eol=c Especifica un carácter de fin de línea (sólo un carácter). skip=n Especifica el número de líneas que se omitirán al principio del archivo. delims=xxx Especifica un grupo de delimitadores. Reemplaza el grupo de delimitadores predeterminado, formado por los caracteres espacio y tabulador. tokens=x,y,m-n Especifica los testigos de cada línea que se pasarán al cuerpo de for en cada iteración. Como consecuencia, se asignarán nombres de variable adicionales. La forma m-n es un intervalo que especifica los testigos m hasta n. Si el último carácter de la cadena tokens= es un asterisco (*), se asigna una variable adicional que contendrá el texto que queda en la línea después del último testigo analizado. usebackq Especifica que se pueden utilizar comillas para incluir los nombres de los archivos de grupoNombreArchivos, que una cadena incluida entre comillas se ejecutará como si fuera un comando y que una cadena escrita entre comillas simples es un comando de cadena literal. Reemplazo de variables: Se han mejorado los modificadores de reemplazo de las referencias a variables de for. La tabla siguiente muestra la sintaxis opcional (para cualquier variable I): Variable con modificador Descripción %~I Expande %I que elimina las comillas (“”) delimitadoras. %~fI Expande %I a un nombre de ruta de acceso completo. %~dI Expande %I a una letra de unidad solamente. %~pI Expande %I a una ruta de acceso solamente. %~nI Expande %I a un nombre de archivo solamente. %~xI Expande %I a una extensión de archivo solamente. %~sI Expande la ruta de acceso para que solamente contenga nombres cortos. %~aI Expande %I a los atributos del archivo. %~tI Expande %I a la fecha y hora del archivo. %~zI Expande %I al tamaño del archivo. %~$PATH:I Busca los directorios enumerados en la variable de entorno PATH y expande %I al nombre completo del primero encontrado. Si el nombre de la variable de entorno no está definido o la búsqueda no encuentra el archivo, este modificador se expande a la cadena vacía. En la tabla siguiente se enumeran las combinaciones de modificadores que se pueden utilizar para obtener resultados compuestos. Variable con modificadores combinados Descripción %~dpI Expande %I a una letra de unidad y una ruta de acceso solamente. %~nxI Expande %I a un nombre y extensión de archivo solamente. %~fsI Expande %I a un nombre completo de ruta de acceso para que solamente contenga nombres cortos.

%~dp$PATH:I Busca los directorios enumerados en la variable de entorno PATH de %I y se expande a la letra de unidad y ruta de acceso del primero encontrado. %~ftzaI Expande %I a una línea de salida parecida a la de dir. En los ejemplos anteriores se puede reemplazar %I y PATH por otros valores válidos. Los nombres de variable válidos de for terminan con la sintaxis %~. Si utiliza nombres de variables en mayúsculas como %I, el código resultará más legible y evitará confusiones con los modificadores, que no distinguen entre mayúsculas y minúsculas. Analizar una cadena: También se puede utilizar la lógica de análisis for /F en una cadena inmediata; para ello, escriba entre comillas simples el grupoNombreArchivos (es decir, ‘grupoNombreArchivos’) que está entre paréntesis. De esta forma, grupoNombreArchivos se considerará como una única línea de entrada de un archivo y se analizará así. Analizar la información de salida: El comando for /F se puede utilizar para analizar la salida de un comando; para ello, se debe escribir entre comillas el grupoNombreArchivos que está entre paréntesis. Así se considerará como una línea de comando, que se pasa a un comando Cmd.exe secundario y la información de salida se captura en la memoria y se analiza como si fuera un archivo. * Ejemplos y comprensión del comando Hasta el momento, únicamente he copiado la definición formal que figura en la propia ayuda de Windows. Voy a darle ahora una vuelta e intentar explicarlo bajo dos puntos de vista que son los básicos de cara a la ejecución de un script: 1) Lectura del “contenido” de un fichero o ficheros Leer el contenido de un fichero, línea por línea, es tan sencillo como usar: for /f %i in (pr.abc pr1.txt) do … lo que queramos El comando anterior leerá todos los ficheros enumerados en la cláusula ‘in’ del directorio en curso y el contenido de ellos, línea por línea lo pasará dentro de la variable i al do de ejecución. Recordemos que en un script el %i debe sustituirse por %%i. Nótese igualmente que esta sintaxis del for no admite caracteres “comodín” en los nombres de archivo, es decir, no podemos referenciarlos por *.abc o bien por ???.abc, sino que el nombre debe estar totalmente cualificado. ¿Cómo podríamos entonces hacer para ver el contenido de todos los archivos con extensión abc? Bien, usando un poco la imaginación y sabiendo que el for normal (sin /f) es capaz de enumerar los archivos en un directorio, podremos endentar dos for para hacerlo. for %i in (*.abc *.txt) do @for /f %j in (%i) do @echo %j (recordemos igualmente que las @ son para no ver la expansión del comando. Cuando estemos depurando una instrucción lo normal es no ponerlas, para poder seguir lo que está haciendo). Evidentemente este es un ejemplo poco agraciado, ya que mediante el comando type podríamos obtener resultados similares, pero viéndolo con un for nos ayuda a comprender el propio for. Compliquémoslo un poco. Queremos el resultado anterior pero ignorando la primera línea de cada archivo. Para ignorar n líneas de un archivo pr.abc sería: for /f “skip=n” %i in (pr.abc) En nuestro ejemplo, por tanto: for %i in (*.abc *.txt) do @for /f “skip=1″ %j in (%i) do @echo %j Sigamos complicándolo un poco más con un ejemplo real: imaginemos que somos administradores de una red y queremos que no se use el emule (o cualquier otro programa) en nuestra red. Una manera sencilla sin entrar a modificar las políticas, seria tener un script en nuestra máquina que periódicamente “matase” los procesos que queramos en las máquinas remotas. La primera idea es que tenemos que tener un fichero con la lista de las máquinas en las cuales

queremos controlar los procesos. Además, deberíamos tener otro dichero con la lista de programas que queremos “matar”. De esta manera, simplemente añadiendo en uno de los ficheros una nueva máquina o en el segundo fichero un nuevo programa, podremos tener siempre planificado un script único que periódicamente analice en las máquinas especificadas en el fichero uno y mate los procesos especificados en el fichero dos. Para ello, creamos un fichero uno con el nombre de las máquinas. Llamemos a ese fichero “máquinas.txt” en el cual escribiremos los nombre o direcciones IP de las máquinas: \\KA0001 \\192.168.0.10 Igualmente crearemos un fichero dos, con el nombre de programas que queremos “matar”. Sea este fichero: programas.txt emule.exe bittorrent.exe Debido a que vamos a acceder a máquinas remotas, se necesita un usuario / password administrador en las máquinas remotas. Deseamos que el script reciba por parámetro el usuario y nos solicite por pantalla la password de ese administrador. Igualmente recordemos un par de comandos de XP Profesional o bien de W2003. Para ver los programas que están en ejecución en una máquina, simplemente teclear en una consola de comandos tasklist. Esto nos muestra la lista de procesos y su PID (número único que identifica un proceso). Recordemos también que el comando taskkill es capaz de matar un proceso pasándole como parámetro el PID del programa a “matar”. Podemos verlo ejecutando en una consola taskkill /? Bien, ya tenemos todos los ingredientes. Ahora ya es trivial la resolución: @echo off if {%1} EQU {} (echo Falta usuario&goto :EOF) setlocal enabledelayedexpansion set user=%1 set /p pass=”password del usuario %1 : ” cls for /f %%f in (máquinas.txt) do call :proc00 %%f endlocal goto :EOF :proc00 for /f “skip=2 tokens=1,2,* delims= ” %%g in (‘tasklist /S %1 /U %user% /P %pass%’) do ( call :proc01 %1 %%g %%h ) goto :EOF :proc01 for /f %%i in (programas.txt) do if {%2} EQU {%%i} taskkill /S %1 /U %user% /P %pass% /PID %3 goto:EOF Podemos modificar el script para no solicitar la password y recibirla también por un segundo parámetro y ponerlo en el planificador de tareas para que se ejecute por ejemplo cada 5 minutos. Las otras máquinas no se enterarán de nada… pero los programas p2p se le “morirán” cada 5 minutos misteriosamente. (Este ejemplo es valido sin cortafuegos. Con cortafuegos deberemos tener abiertos el puerto netbios-ssn que es el que usan los comandos tasklist y taskkill). En www.sysinternals.com existe una utilidad llamada pskill, pslist las cuales también funcionan en XP Home (que no posee los comandos anteriores). Como ejercicio, os podéis bajar dichas utilidades, ejecutarlas en consola para ver cómo son dichas salidas y preparar un script similar con ellas. Vamos a comentar algunas características usadas en el script anterior:

in (‘tasklist /S %1 /U %user% /P %pass%’) Fijémonos en la comilla simple que delimita al comando tasklist y sus parámetros. Cuando dentro de un for /f en la parte del in, especificamos algo encerrado entre comillas simples lo que estamos haciendo es ordenando que se ejecute ese comando en un cmd aparte y que cuando finalice, la salida que nos mostraría en pantalla (STDIN) de la pase al for directamente. Esto lo veremos en detalle en la parte 2) de este capítulo. Por tanto es como si se ejecutase el tasklist y lo que se vería por pantalla se le pasa al for. Evidentemente toda esa salida (probarla por pantalla) debe filtrarse para separar los campos que necesitamos, ya que primero: nos molestan las líneas de cabecera y segundo: en las líneas de detalle tenemos que separar lo que es el nombre del programa de lo que es el PID y el resto de datos (que nos sobran en este caso). Es decir, si ejecutamos tasklist en nuestra máquina veremos algo así: Image Name PID Session Name Session# Mem Usage ================ === ================ ======== ============ System Idle Process 0 Console 0 24 K System 4 Console 0 252 K smss.exe 412 Console 0 644 K csrss.exe 524 Console 0 5.848 K winlogon.exe 564 Console 0 5.512 K services.exe 608 Console 0 6.208 K ………. Fijémonos ahora por delante de la cláusula “in” que es lo que hay: “skip=2 tokens=1,2,* delims= ” %%g Con esto le estamos diciendo: a) Que ignore las dos primeras líneas. b) En tokens, le estamos indicando que vamos a coger el primer campo (que lo pondrá en %%g), el segundo, (que lo pondrá en %%h) y el resto (que lo pondrá en %%i). Fijémonos que sólo hemos definido %%g en la línea, pero al especificar más campos, usará las letras alfabéticamente a partir de %%g como nombres de variables. c) en delims= (nótese un espacio en blanco al final), le estamos diciendo que considere delimitadores los caracteres que van a continuación del símbolo igual, por tanto en nuestro caso le estamos diciendo que sólo hay un delimitador y que este delimitador son los espacios en blanco. Por tanto la instrucción: for /f “skip=2 tokens=1,2,* delims= ” %%g in (‘tasklist /S %1 /U %user% /P %pass%’) do… Está recuperando en %%g el nombre de cada proceso y en %%h el PID de dicho proceso. Creo que con este pequeño resumen puede comprenderse perfectamente la potencia del for. Analizar despacio ahora el resto del script. 2) Ejecución de “instrucciones o comandos” dentro del for (en la cláusula in) Hemos introducido anteriormente en el ejemplo de la parte 1) que dentro del “in” puede ir entrecomillado simple el nombre de un programa o comando y que el sistema lo ejecutará. Vamos a ver cómo se realiza esto y cómo se recuperan los datos: Lo existente entrecomillado simple dentro de un in en un comando for /f se ejecutará abriendo (en forma oculta) otro “cmd” el cual ejecutará el comando. La salida a consola (STDOUT) de ese comando cuando finalice, será la que se pase línea por línea al for invocante. Hay una manera de comprobar esto. Abrimos un administrador de tareas y ordenamos por el “Nombre de imagen” -pinchado ascendente o descendentemente- en la pestaña procesos. De esta manera vemos cuantos cmd.exe tenemos en ejecución. Ahora nos creamos un simple script (pr.cmd) que haga: @echo off dir

pause Esto sacaría un “dir” y esperaría hasta que pulsemos una tecla. En vez de ejecutarlo directamente vamos a ejecutarlo desde dentro de un for for /f “tokens=*” %i in (‘pr.cmd’) do @echo %i El ejecutar lo anterior ¿qué pasa? Ejecutémoslo. Lo primero que vemos es que se queda parado. Fijémonos también en el administrador de tareas: hay un “cmd.exe” más en ejecución de forma oculta ya que no hay consola que veamos, y que realmente es el que esta ejecutando el pr.cmd y está parado en la instrucción “pause”. Nuestro for todavía no ha devuelto datos, por tanto, aunque el dir del pr.cmd se ha ejecutado, todavía no ha devuelto contenido al for. Si ahora tecleamos cualquier cosa en la única consola que tenemos abierta, esta entrada se pasará al segundo cmd (es decir, redirige también el STDIN). En ese momento, en la segunda consola (oculta) al recibir la tecla, continúa y finaliza. En el momento de la finalización es cuando devuelve los datos, línea por línea al for. Programación BATCH Avanzada. Temario. 1.- Variables y Argumentos. 2.- Imprimir caracteres de comandos. 3.- Algunas otras variables de Entorno. 4.- IF 5.- FOR 6.- Funciones 7.- Includes 8.- Misc 9.- EOF

Variables y Argumentos El manejo de variables en batch, es muy flexible., y este nos permite hacer desde operaciones matemáticas, hasta seleccionar ciertas partes de una variable, asi como reemplazar cadenas de texto, y obtener archivos.. y sus propiedades, la fecha, hora, generar numeros aleatorios, entre otros. Los argumentos que recibe un batch, son recibidos de la siguiente forma: batch argumento1 dos tres hara que: %0 = batch %1 = argumento1 %2 = dos %3 = tres

en %0 se guardara, el nombre del archivo. Podemos borrar el contenido de un parametro con el comando shift: Código 1. 2. 3. 4. 5.

@echo off echo %0 %1 %2 %3 shift /1 echo %0 %1 %2 %3

al llamar: Código 1. C:\Documents and Settings\Administrador\tempcurso>astring 123 456 789 2. astring 123 456 789 3. astring 456 789 4.

shift borro, el primer argumento. Tambien contamos con los siguientes modificadores para los archivos: Código 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

%~f1 %~d1 %~p1 %~n1 %~x1 %~s1 %~a1 %~t1 %~z1

- regresa la ruta y el archivo de %1. - regresa la letra de la unidad de %1. - regresa solo la ruta del archivo %1. - regresa solo el nombre de archivo %1. - regresa solo la extension del archivo %1. - regresa solo la ruta, con directorios, con nombres cortos del archivo %1. - regresa los atributos del archivo. - regresa la hora/fecha del archivo %1 - regresa el tamaño del archivo %1.

por ejemplo: en un directorio donde tenemos: Código 1. C:\Documents and Settings\Administrador\tempcurso>dir 2. El volumen de la unidad C no tiene etiqueta.

3. El número de serie del volumen es: A057-553B 4. 5. Directorio de C:\Documents and Settings\Administrador\tempcurso 6. . 7. 24/07/2006 12:25a 8. 24/07/2006 12:25a .. 9. 24/07/2006 12:25a 6 archivo.txt 10. 1 archivos 6 bytes 11. 2 dirs 401,715,161,088 bytes libres 12.

este batch: Código 1. @echo off 2. echo Ruta al archivo: %~f1 3. echo Disco: %~d1 4. echo Solo ruta: %~p1 5. echo Nombre: %~n1 6. echo Extension: %~x1 7. echo Ruta Corta: %~s1 8. echo Atributos: %~a1 9. echo Fecha: %~t1 10.echo Tamaño: %~z1 11.

llamandolo analiza.bat, saca el siguiente resultado: Código 1. C:\Documents and Settings\Administrador\tempcurso>analiza archivo.txt 2. Ruta al archivo: C:\Documents and Settings\Administrador\tempcurso\archivo.txt 3. Disco: C: 4. Solo ruta: \Documents and Settings\Administrador\tempcurso\ 5. Nombre: archivo 6. Extension: .txt 7. Ruta Corta: C:\DOCUME~1\ADMINI~1\TEMPCU~1\archivo.txt 8. Atributos: --a-----9. Fecha: 24/07/06 12:25a 10.Tama±o: 6 11.

Tambien podemos usar varias propiedades, por ejemplo, este codigo: Código

1. @echo off 2. 3. echo %~anxt1 4.

saca este resultado: Código 1. C:\Documents and Settings\Administrador\tempcurso>analiza archivo.txt 2. --a------ 24/07/06 12:25a archivo.txt 3.

Si lo que recibimos no es un archivo, sino una cadena de texto, que contiene mas de una palabra, se debe poner entre comillas, algo asi: astring "parametro de varias letras" al obtenerlo, en %1, lo recibimos con comillas, pero si usamos: Código 1. @echo off 2. echo Con Comillas: %1 3. echo Sin Comillas: %~1 4.

saca este resultado: Código 1. C:\Documents and Settings\Administrador\tempcurso>astring "parametro de varias letras" 2. Con Comillas: "parametro de varias letras" 3. Sin Comillas: parametro de varias letras 4.

Y por ejemplo, si queremos obtener todos los argumentos, se usa: %* es decir: Código 1. @echo off

2. 3. echo Argumentos: %* 4.

al ejecutar: astring parametro de varias letras nos regresa: Código 1. C:\Documents and Settings\Administrador\tempcurso>astring parametro de varias letras 2. Argumentos: parametro de varias letras

Para asignar a una variable, el valor de algo escrito por el usuario, puedes usar: set /P variable= por ejemplo: Código 1. 2. 3. 4. 5. 6.

@echo off echo ¿Como te llamas? set /P miva= echo Tu te llamas %miva%

hara algo asi: Código 1. 2. 3. 4. 5.

C:\Documents and Settings\Administrador\tempcurso>astring ┐Como te llamas? Juan Tu te llamas Juan

Ahora, si por ejemplo, queremos, hacer algo como, obtener las ultimas 3 letras del nombre: Código 1. @echo off

2. echo Escribe tu Nombre 3. set /P NOM= 4. echo %NOM:~-3% 5.

Aqui lo que estamos haciendo en la ultima linea: %NOM:~-3% hara, obtener los ultimos 3 caracteres, como si se tratara de la funcion substring. por ejemplo, esto: %NOM:~1,3% obtendra del segundo al cuarto caracter. (empiezas desde 0, recuerda) Para reemplazar cadenas, dentro de otra variable, es la siguiente sintaxis: Código 1. 2. 3. 4.

@echo off echo Escribe una frase set /P FRA= echo %FRA:e=XXX%

esto reemplazara las letras "e" por "XXX". Para hacer calculos matematicos, se usa el modificado /A, de esta forma: Código 1. 2. 3. 4. 5. 6.

@echo off set /A x=1 echo %x% set /A x=x*9 echo %x%

tenemos las siguientes operaciones disponibles: Código 1. () 2. * / % 3. + -

- agrupar - operadores aritméticos - operadores aritméticos

4. > - mayús lógica 5. & - AND - XOR 6. ^ - OR 7. | 8. = *= /= %= += -= - asignación 9. &= ^= |= = 10., - separador de expresión 11.

Con este podemos usar numeros hexadecimales de la siguiente forma: Código 1. 2. 3. 4. 5.

@echo off set /A x=2 echo %x% set /A x=x*0xff echo %x%

al colocar 0x estamos especificando, que a continuacion se pondra un valor hexadecimal.

Imprimir caracteres sin usar comandos Ahora, se preguntaran, en las variabes, siempre usamos los signos % Como imprimes uno? veamos: Código 1. @echo off 2. set x=pru 3. set pru=HOLA 4. 5. :: Esto imprimira el contenido de x 6. echo %x% 7. 8. ::Esto imprimira la letra x 9. echo x 10. 11.::Esto imprimira %x% 12.echo %%x%% 13. 14.::Esto imprimira el valor de x entre %% 15.echo %%%x%%%

16. 17.:: Lo mismo 18.echo %pru% 19.echo %%pru%% 20.echo %%%pru%%% 21.

En resumen, si quieren imprimir, el caracter %, deben colocarlo 2 veces. Para otros caracteres, que ejecutan alguna accion en batch como: & | < > debes colocar este caracter antes:^ por ejemplo: Código 1. echo Hola >index.html 2.

no funcionara, pero: Código 1. echo ^^Hola^^ >index.html 2.

dara: Código 1. C:\Documents and Settings\Administrador\tempcurso>type index.html 2. Hola 3.

Algunas otras variables de entorno

Tenemos otras variables de entorno que podrian servir, ademas de las comunes de ALLUSERSPROFILE y HOMEPATH, por ejemplo: Código 1. 2. 3. 4. 5. 6.

@echo off echo Directorio Actual: %CD% echo Fecha: %DATE% echo Hora: %TIME% echo Numero Aleatorio: %RANDOM%

dara como resultado: Código 1. C:\Documents and Settings\Administrador\tempcurso>astring 2. Directorio Actual: C:\Documents and Settings\Administrador\tempcurso 3. Fecha: Lun 24/07/2006 4. Hora: 2:13:49.33 5. Numero Aleatorio: 24523 6. 7. C:\Documents and Settings\Administrador\tempcurso>astring 8. Directorio Actual: C:\Documents and Settings\Administrador\tempcurso 9. Fecha: Lun 24/07/2006 10.Hora: 2:13:51.60 11.Numero Aleatorio: 3681 12.

Otras instrucciones muy utiles, serian POPD y PUSHD, que sirven para guardar y regresar al directorio actual, por ejemplo: Código 1. 2. 3. 4. 5. 6. 7.

@echo off echo %CD% PUSHD \ echo %CD% POPD echo %CD%

PUSHD funciona de la siguiente manera: Guarda el directorio actual., y va a la ruta especificada. POPD regresa al directorio guardado por PUSHD

podemos usarlos uno dentro de otro, asi: Código 1. @echo off 2. echo %CD% 3. PUSHD \ 4. echo %CD% 5. PUSHD %homepath% 6. echo %CD% 7. POPD 8. echo %CD% 9. POPD 10.echo %CD% 11.

IF If, reconoce varias situaciones: valores de error comparar cadenas existencia de archivos comparaciones matematicas como ya sabemos %ERRORLEVEL% almacena algunos valores de otras funciones. al hacer IF ERRORLEVEL 1 @echo ok ELSE @echo no estariamos preguntando si ERRORLEVEL es 1, si lo es imprime OK, si no, imprime NO. tambien podemos comparar cadenas, por ejemplo: Código 1. @echo off 2. IF "%~1"=="hola" echo hola 3.

usamos %~1 para que aunque el usuario ponga comillas, no salga error Código 1. @echo off 2. IF /I "%~1"=="hola" echo hola 3.

este codigo, solo responde si dices hola CON minusculas. /I es para hacer mas estricta la comparacion. ahora, podemos usar IF en varias lineas: Código 1. 2. 3. 4. 5. 6. 7.

@echo off IF EXIST %~snx1 ( echo EXISTE! ) ELSE ( echo NO EXISTE )

con parentesis (). si vamos a usar comparaciones numericas, debemos usar los siguientes codigos de comparación: Código 1. 2. 3. 4. 5. 6. 7. 8. 9.

EQU - igual NEQ - no igual LSS - menor que LEQ - menor que o igual GTR - mayor que GEQ - mayor que o igual

por ejemplo: Código 1. @echo off 2. echo Cual es tu edad?

3. 4. 5. 6. 7. 8. 9.

SET /P m= IF %m% GEQ 18 ( echo ERES MAYOR DE EDAD ) ELSE ( echo NO ERES MAYOR DE EDAD )

que regresa: Código 1. C:\Documents and Settings\Administrador\tempcurso>acon 2. Cual es tu edad? 3. 19 4. ERES MAYOR DE EDAD 5. 6. C:\Documents and Settings\Administrador\tempcurso>acon 7. Cual es tu edad? 8. 17 9. NO ERES MAYOR DE EDAD 10.

Tambien podemos saber si una variable ya fue definida: Código 1. 2. 3. 4. 5. 6.

IF DEFINED var ( echo SI ) ELSE ( echo NO )

FOR FOR es una herramienta muy completa, nos permite analizar segmentos de la salida de comandos, funciones y el contenido de archivos. Tambien permite hacer bucles de la siguiente manera: Código

1. FOR /L %%var IN (inicio,incremento,fin) DO (acciones)

inicio, es el valor inicial, incremento es la cantidad a sumar, y fin es la cantidad a detenerse, por ejemplo: Código 1. FOR /L %%i IN (0,1,10) DO (echo %%i) imprimira 0 1 2 3 4 5 6 7 8 9 10 sinembargo, la forma mas sencilla de usar FOR, es para numerar archivos, y hacer algo con ellos.. por ejemplo: Código 1. FOR %%x in (x*) DO echo %%x mostrará todos los archivos que empiezan con x. para SOLO mostrar directorios: Código 1. FOR /D %%x in (m*) DO echo %%x el modificador "/D", mostrará solo los directorios, que empiesen con m. El comando se puede hacer "recursivo", es decir, que se ejecute dentro de cada directorio, con el comando "/R", por ejemplo, en una estructura de directorios como la siguiente: Código 1. 2. 3. 4. 5.

├───adios │ └───algo │ └───xx └───hola

al ejecutar el comando: Código 1. FOR /R /D %%x in (a*) DO echo %%x 2. C:\adios 3. C:\adios\algo

sinembargo, al ejecutar el comando.. Código 1. 2. 3. 4. 5. 6. 7. 8.

FOR /R %%x in (*x*) DO echo %%x C:\ax.txt C:\adios\sx.txt C:\adios\wwx.txt C:\adios\algo\kkx.txt C:\adios\algo\xx\xx.txt C:\hola\ax.txt C:\hola\rx.txt

nos mostrara todos los archivos que coinciden con la sequencia especificada, incluso podriamos hacer un buscador en batch, con el uso de FINDSTR y FOR. Tenemos otro modificador, /F que nos permite usar ciertas opciones para separar el resulado de las acciones.. comandos, cadenas, o archivos. Su sintaxis es la siguiente: Código 1. FOR /F ["opciones"] %var IN (conjunto) DO (acciones)

conjunto puede ser: conjunto de archivos -> sin comillas cadena de caracteres -> con comillas dobles (" ") comando -> con comilla simple (' ') las opciones son las siguientes: eol -> todo lo que este despues de este caracter sera ignorado (para cada linea) skip -> numero de lineas a saltarse al principio del archivo/comando. delims -> esto sirve para separar las strings.. si no se coloca esta opcion, se usaran como separadores "espacio" y "tab" tokens -> esto es para especificar cuales segementos, delimitados por "delims", seran pasados a las variables.. por ejemplo: 1,2,3 solo pasara los primeros 3 segmentos. 1,2* pasara 2 segmentos, el primero y todo lo que este despues (el * regresa todo el resto de la linea) 1,2-6,8,9* regresara 4 segmentos, el primero, desde el segundo hasta el sexto, el octavo y el resto de la linea, despues del noveno, el signo de menos (-) genera intervalos.

por ultimo, esta la opcion: usebackq -> que cambia la forma de interpretar si es string o comando, de la siguiente manera: 'cadena' `comando` Nota: [`] es diferente al caracter de acento [´] por ejemplo, el siguiente comando: Código 1. FOR /F "tokens=1,3-5,7-9,10* delims= " %%i IN ("George no es malvado, es bondadoso, siempre piensa en los demas.") DO echo %%i %%j %%k %%l tonto, %%m %%n %%o matar a %%p %%q

dara de resultado: Código 1. George es malvado, es tonto, siempre piensa en matar a los demas.

Funciones El uso de argumentos, de etiquetas y de filtros nos ayuda mucho al momento de escribir un codigo. Muchos creen que las etiquetas solo sirven para los goto.. sinembargo una etiqueta puede servir de funcion y recibir parametros. miren, el siguiente programa: Código 1. 2. 3. 4. 5. 6.

@echo off call:funcion 1 2 3 call:funcion %* goto:EOF :funcion echo Estoy en: %~nx0-^>%0 %*

al ser llamado, por ejemplo en:

Código 1. C:\>ejemplo 2. Estoy en: ejemplo.bat->:funcion 1 2 3 3. Estoy en: ejemplo.bat->:funcion el primero muestra los parametros enviados por el batch (1 2 3), y el segundo los parametros enviados al programa. en este otro ejemplo: Código 1. C:\>ejemplo HOLA MUNDO 2. Estoy en: ejemplo.bat->:funcion 1 2 3 3. Estoy en: ejemplo.bat->:funcion HOLA MUNDO la funcion obtiene tambien los argumentos del programa. hasta ahora.. todo es igual a usar goto a excepcion del uso de argumentos, sinembargo.. si queremos hacer un.. "return", se hace usando: goto:EOF entonces, en situaciones como: Código 1. @echo off&call:main&goto:EOF 2. 3. :suma 4. set /A res=%1 + %2 5. echo %res% 6. goto:EOF 7. 8. :resta 9. set /A res=%1 - %2 10.echo %res% 11.goto:EOF 12. 13.:multiplica 14.set /A res=%1 * %2 15.echo %res% 16.goto:EOF 17. 18.:main 19.set /P arg=Escribe 2 numeros separados por un espacio 20.echo %arg% 21.echo su suma es: 22.call:suma %arg% 23. 24.echo su resta es:

25.call:resta %arg% 26. 27.echo su producto es: 28.call:multiplica %arg% 29. 30.goto:EOF 31.

como podemos ver goto:EOF se usa para regresar al orden de comandos. el resultado es algo asi: Código 1. C:\>operaciones 2. Escribe 2 numeros separados por un espacio 6 2 3. 6 2 4. su suma es: 5. 8 6. su resta es: 7. 4 8. su producto es: 9. 12 10.

Includes Para hacer un "include" oincluir un archivo, solo debes llamarlo asi: archivo_a_incluir.bat funcion argumentos y en el archivo a incluir, debe de estar al principio: @echo off&call:%*&goto:EOF queda algo asi: Código 1. 2. 3. 4. 5. 6.

@echo off&call:%*&goto:EOF :funcion1 ... :funcion2 ...

por ejemplo:

--inclu.bat-Código 1. @echo off&call:%*&goto:EOF 2. 3. :cabeza 4. echo ############### 5. echo # Hecho por: # 6. echo # sirdarckcat # 7. echo ############### 8. goto:EOF 9. 10.:uso 11.echo uso: 12.echo %~nx0 Nombre 13.goto:EOF 14. 15.:nombre 16.echo Hola %* 17.goto:EOF 18.

--inicio.bat-Código 1. 2. 3. 4. 5. 6. 7. 8.

@echo off if "%~1"=="" ( inclu.bat cabeza inclu.bat uso ) else ( inclu.bat nombre %~1 )

esto daria este resultado: Código 1. 2. 3. 4. 5. 6. 7.

C:\>inicio ############### # Hecho por: # # sirdarckcat # ############### uso: inclu.bat Nombre

8. 9. C:\>inicio sirdarckcat 10.Hola sirdarckcat 11. 12.C:\> 13.

Misc Algunos filtros y comandos interesantes: •

comando | more

muestra el resultado del comando de forma paginada •

comando | sort

muestra el resultado del comando de forma ordenada •

TITLE "algo"

cambia el titulo de la ventana de CMD •

SUBST ruta/a/alguna/carpeta [letra_unidad]

asgina a letra_unidad la ruta de acceso •

FIND "cadena"

busca cierta cadena en un archivo (se puede usar como filtro), con el modificador /v encuentra solo las que NO tienen la linea especificada. (para mas info, escribe en CMD: FIND /?) •

FINDSTR

extension de FIND, acepta expresiones regulares, y busqueda general (lo mas parecido que DOS tiene a grep), descripción detallada: Código 1. Busca cadenas en los archivos. 2. 3. FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] 4. [/F:archivo] 5. [/C:cadena] [/G:archivo] [/D:lista de directorios] [/A:atributos de color] 6. [cadenas] [[unidad:][ruta]nombredearchivo[ ...]] 7. 8. /B Hace coincidir los modelos si están al principio de la línea.

9. /E Hace coincidir los modelos si están al final de la línea. 10. /L Literalmente utiliza cadenas de búsqueda. 11. /R Utiliza cadenas sde búsqueda como expresiones regulares. 12. /S Busca archivos que coinciden en el directorio actual y en todos 13. los subdirectorios. 14. /I Especifica que la búsqueda no distingue mayúsculas de minúsculas. 15. /X Imprime líneas que coinciden con exactitud. 16. /V Sólo imprime líneas que no contienen una correspondencia. 17. /N Imprime el número de la línea antes de la línea que coincide. 18. /M Sólo imprime el nombre de archivo si el archivo contiene una 19. correspondencia. 20. /O Imprime un carácter de desplazamiento antes de las líneas que 21. coinciden. 22. /P Omite archivos con caracteres que no son imprimibles 23. /A:attr Especifica atributos de color con dos dígitos hexadecimales. Ver 24. "color /?" 25. /F:archivo Lee la lista de archivos desde el archivo especificado 26. (/ significa consola). 27. /C:cadena Utiliza una cadena especificada como una búsqueda de cadena 28. literal. 29. /G:archivo Coje la búsqueda de archivos desde el archivo especificado (/ significa consola). 30. 31. /D:dir Busca un signo de punto y coma de la lista delimitada de 32. directorios 33. cadenas Texto que se debe buscar. 34. [unidad:][ruta]nombredearchivo 35. Especifica un archivo o archivos que buscar. 36. 37.Utiliza espacios para separar múltiples cadenas de búsqueda a no ser que 38.el argumento lleve un prefijo con /C. Por ejemplo, 'FINDSTR "qué tal" x.y' 39.busca "qué" o "tal" en el archivo x.y. 'FINDSTR /C:"qué tal" x.y' busca 40."qué tal" en el archivo x.y. 41. 42.Expresión regular de referencia rápida: 43. . Comodín: cualquier carácter 44. * Repetir: cero o más ocurrencias de un carácter previo o de clase 45. ^ Posición de línea: comienzo de la línea 46. $ Posición de línea: fin de línea 47. [clase] Clase de carácter: cualquier carácter en la serie 48. [^class] Clase inversa: cualquier carácter que no esté en la serie 49. [x-y] Intervalo: cualquier carácter que esté dentro del intervalo 50. especificado 51. \x Escape: uso literal de un metacarácter x 52. \ Posición de palabra: fin de palabra 54. 55.Para obtener una información más completa sobre expresiones regulares de 56.FINDSTR referirse al Comando de referencia Command en línea. 57. 58.



start "titulo ventana nueva" [OPCIONES] comando argumentos

START tiene mas opciones de las que son usadas comunmente. "titulo ventana nueva" especifica el titulo de la ventana que se generará. las opciones entre otros contienen: /Druta - el programa inicia en el directorio.. /B - la aplicación se inicia sin ventana /I - se inicia la aplicacion con el entorno original, es decir las modificaciones al entrono hechas en esta sesion, no afectaran el nuevo programa /MIN - La nueva ventana se inicia minimisada /MAX - La nueva ventana se inicia maximisada /SEPARATE - El programa se inicia en una zona de memoria separada /SHARED - El programa se inicia en una zona de memoria compartida Iniciar en prioridades: /LOW - baja /NORMAL - normal /HIGH - alta /REALTIME - tiempo real /ABOVENORMAL - sobre lo normal /BELOWNORMAL - debajo de lo normal /WAIT - Inicia el programa, y espera hasta que termine de ejecutarse por ejemplo, si quieren abrir un programa sin generar una ventana, por ejemplo netcat, podrian hacer algo asi: start /B /SEPARATE /HIGH /I /D %WINDIR% nc -L -p 1337 |exit que lo inicia en una zona de memoria separada, con prioridad alta, en el contexto original, y en %windir%

EOF EOF es una etiqueta que define el fin del archivo, sirve para terminar funciones, y en este caso, solo sirve para terminar el documento , espero les sirva TITLE cadena

Fija el título de la ventana en la ventana del símbolo del sistema.

PROMPT [texto] Cambia el símbolo del sistema de cmd.exe. texto Especifica un nuevo símbolo del sistema. En el símbolo del sistema se pueden escribir caracteres normales y los siguientes códigos especiales: $A $B $C $D $E $F $G $H $L $N $P $Q $S $T $V $_ $$

& (Símbolo de unión) | (barra vertical) ( (Paréntesis izquierdo) Fecha actual Código de escape (código ASCII 27) ) (Paréntesis derecho) > (signo mayor que) Retroceso (elimina el carácter previo) < (signo menor que) Unidad actual Unidad y ruta de acceso actual = (signo igual) (espacio) Hora actual Versión de Windows XP Retorno de carro y alimentación de línea $ (signo del dólar)

Si las Extensiones de comando están habilitadas, el comando PROMPT admite los siguientes caracteres de formato adicionales: $+ cero o más caracteres de signo "más" (+) en función de la profundidad del directorio de pila PUSHD, un carácter por cada nivel insertado. $M Muestra el nombre remoto asociado a la letra de unidad actual o la cadena vacía si la unidad actual no es una unidad de red. COLOR nº1nº2 Configura los colores predeterminados de primer y segundo planode la consola. Especificados con dos dígitos hex: el primero corresponde al fondo; el segundo al texto. 0 = Negro 8 = Gris 1 = Azul 9 = Azul claro 2 = Verde A = Verde claro 3 = Aguamarina B = Aguamarina claro 4 = Rojo C = Rojo claro 5 = Púrpura D = Púrpura claro 6 = Amarillo E = Amarillo claro 7 = Blanco F = Blanco brillante Si no se indican argumentos, este comando restaura el color que teníacuando se inició CMD.EXE. Este valor proviene de la ventanade la consola, el modificador de línea de comando o el valor del registro DefaultColor.

El comando COLOR configura ERRORLEVEL a 1 si se realiza un intento de ejecutar el comando COLOR con el mismo color de primer y segundo plano BREAK: Activa o desactiva Ctrl+C extendido en DOS Está presente para que haya compatibilidad con sistemas DOS, pero no tiene efecto en Windows XP. Si se activan las extensiones de comando y se ejecuta en la plataforma deWindows XP, el comando BREAK introducirá un punto de ruptura dentro del código, si está siendo depurado por un depurador. CHCP [nnn] nnn Especifica una página de códigos. Escriba CHCP sin parámetro para mostrar el número de la tabla de códigos activa. GRAFTABL [xxx] Permite que Windows muestre caracteres extendidos en modo gráfico. Similar a chcp xxx Especifica el número de la tabla de códigos. /STATUS Muestra la tabla de códigos seleccionada para usar con GRAFTABL. SET [variable=[cadena]]

Muestra, establece o quita las variables de entorno de cmd.exe.

variable Especifica el nombre de la variable de entorno. cadena Especifica una serie de caracteres que se asignará a la variable. Escriba SET sin parámetros para ver las variables de entorno actuales. Si las extensiones de comando están habilitadas, SET cambia así: "Cuando se llama al comando SET solamente con un nombre de variable, sin signo de igual ni valor, se mostrarán los valores de todas las variables cuyos prefijos coincidan con el nombre especificado como parámetro para el comando SET. Por ejemplo: SET P

mostrará todas las variables que empiecen con la letra 'P'

El comando SET establecerá ERRORLEVEL en 1 si no se encuentra el nombre de la variable en el entorno actual. El comando SET no permitirá que un signo de igual sea parte de una variable. Se han agregado dos modificadores nuevos al comando SET: SET /A expression SET /P variable=[promptString] El modificador /A especifica que la cadena a la derecha del signo de iguales una expresión numérica que es evaluada. El evaluador de expresiones esbastante simple y es compatible con las siguientes operaciones, en orden de precedencia decreciente: () !~-

- agrupar - operadores unarios

*/% - operadores aritméticos +- operadores aritméticos > - desplazamiento lógico & - bit a bit y ^ - bit a bit exclusivo o | - bit a bit = *= /= %= += -= - asignación &= ^= |= = , - separador de expresión Si se utiliza cualquiera de los operadores lógicos o de módulo, será necesario escribir la cadena entre comillas. Cualquier cadena de la expresión que no sea numérica, se tratará como variable de entorno cuyo valor se convertirá a tipo numérico antes de utilizarse. Si se especifica una variable que no está definida en el entorno actual, se utilizará el valor cero. Esto permite hacer operaciones aritméticas con los valores de variables de entorno evitando el escribir todos estos signos % para obtener sus valores. Si se ejecuta el comando SET /A desde la línea del comando fuera de la secuencia decomandos, entonces se mostrará el valor final de la expresión. El operador de asignación requiere un nombre de variable de entorno a la izquierda del operador de asignación. Los valores numéricos son números decimales, a no ser que lleven el prefijo 0x delante para los números hexadecimales, y 0 para los números octales. De esta manera 0x12 es lo mismo que 18, y lo mismo que 022. Nota: la notación octal puede ser confusa: 08 y 09 no son números válidos porque 8 y 9 no son dígitos octales válidos. El modificador /P permite establecer el valor de una variable para una líneade entrada escrita por el usuario. Muestra la cadena del símbolo del sistema antes de leer la línea de entrada. La cadena del símbolo del sistema puede estar vacía. La sustitución de variables de entorno ha sido mejorada así: %PATH:str1=str2% expandirá la variable de entorno PATH, sustituyendo cada repetición de "str1" en el resultado expandido con "str2". "str2" puede ser la cadena vacía para borrar efectivamente todas las repeticiones de "str1" de la salida expandida. "str1" puede empezar con un asterisco, en cuyo caso,coincidirá con lo contenido en la salida expandida desde su inicio, hasta la primera aparición del fragmento de str1 que queda. También puede especificar subcadenas para una expansión. %PATH:~10,5% expandirá la variable de entorno PATH, y usará sólo los 5 caracteres a partir del décimo primer carácter (desplazamiento 10) del resultado expandido. Si la longitud no se especifica, se utilizará el resto del valor de la variable. Si algún número (desplazamiento o longitud) es negativo, entonces el número usado es la longitud del valor de la variable de entorno añadido al desplazamiento o longitud especificados.

%PATH:~-10% extraerá los 10 caracteres de la variable PATH. %PATH:~0,-2% extraerá todo menos los 2 últimos caracteres de la variable PATH. Finalmente, se ha añadido compatibilidad para la expansión de la variable retardada. Este soporte está siempre deshabilitado de forma predeterminada, pero puede habilitarse o deshabilitarse a través del modificador de línea de comandos /V a CMD.EXE. Ver CMD /? La expansión de la variable de entorno es útil para tratar con las limitaciones de la expansión actual, las cuales ocurren cuando una línea de texto es leída, y no cuando se ejecuta. El siguiente ejemplo demuestra el problema con la expansión de la variable inmediata: set VAR=antes if "%VAR%" == "antes" ( set VAR=después if "%VAR%" == "después" @echo Si esto se puede ver, entonces significa que funcionó ) dado que %VAR% se sustituye al mismo tiempo en ambas instrucciones IF cuando se lee la primera instrucción IF, pues incluye lógicamente al cuerpo del IF, el cual es una instrucción compuesta. De esta manera, IF, dentro de la instrucción compuesta está realmente comparando "antes" con "después" lo cuál nunca será igual. De un modo parecido, el siguiente ejemplo no funcionará como se espera: set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST% en esto NO generará una lista de archivos en el directorio actual, pero en su lugar establecerá la variable LIST en el último archivo encontrado. De nuevo, esto ocurre porque %LIST% es expandido sólo una vez cuando la opción FOR es leída, y en ese momento la variable LIST variable está vacía. Así el ciclo actual FOR que se está ejecutando es: for %i in (*) do set LIST= %i el cual sólo mantiene el valor LIST hasta el último archivo encontrado. La expansión de la variable de entorno retardada permite utilizar un carácter diferente (el signo de exclamación para expandir variables en tiempo de ejecución. Si la expansión de la variable retardada está habilitada, los ejemplos se pueden escribir de la siguiente manera para que funcionen como es necesario: set VAR=antes

if "%VAR%" == "antes" ( set VAR=después if "!VAR!" == "después" @echo Si esto se puede ver, entonces significa que funcionó ) set LIST= for %i en (*) do set LIST=!LIST! %i echo %LIST% Si las extensiones de comando están habilitadas, hay varias variables dinámicas de entorno que pueden ser expandidas pero que no se muestran en la lista de variables que muestra ESTABLECER. Estos valores de variable se calculan dinámicamente cada vez que el valor de la variable se expande. Si el usuario define una variable explícitamente con uno de estos nombres, entonces esa definición suplantará la variable dinámica abajo descrita: %CD% - se expande a la cadena del directorio actual . %DATE% - se expande a la fecha actual usando el mismo formato que el comando DATE. %TIME% - se expande a la hora actual usando el mismo formato que el comando TIME. %RANDOM% - se expande a un número decimal aleatorio entre 0 y 32767. %ERRORLEVEL% - se expande al valor de NIVEL DE ERROR actual %CMDEXTVERSION% - se expande al número actual de versión de las extensiones del comando del procesador. %CMDCMDLINE% - se expande a la línea de comando original que invocó el Procesador de comandos.

CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF] [[/S] [/C | /K] cadena] Inicia una nueva instancia del intérprete de comandos de Windows

/C Ejecuta el comando especificado en cadena y luego finaliza /K Ejecuta el comando especificado en cadena pero sigue activo /S Modifica el tratamiento de cadena después de /C o /K (consultar

más abajo) /Q Deshabilita el eco /D Deshabilita le ejecución de los comandos de AutoRun del registro (consultar más abajo) /A Utiliza ANSI para la salida de comandos internos hacia una canalización o un archivo /U Utiliza UNICODE para la salida de comandos internos hacia una canalización o un archivo /T: fg Configura los colores de primer y segundo plano (para obtener más información, consulte COLOR /?) /E:ON Habilita las extensiones de comando (consultar más abajo) /E:OFF Deshabilita las extensiones de comando (consultar más abajo) /F: ON Habilita los caracteres de terminación de los nombres de archivos y directorios (consultar más abajo) /F: OFF Deshabilita los caracteres de terminación de los nombres de archivos y directorios (consultar más abajo) /V: ON Habilita la extensión de variables de entorno retardada usando ! como delimitador. Por ejemplo, /V: ON permitirá que !var! extienda la variable var en tiempo de ejecución. La sintaxis var extiende variables en tiempo de entrada, lo cual es diferente cuando se está dentro de un bucle FOR. /V: OFF Deshabilita la extensión de variables de entorno retardada. Tenga en cuenta que los comandos múltiples separados por el separador de comandos '&&' se aceptan como cadena si están entre comillas. Por razones de compatibilidad, /X equivale a /E:ON, /Y equivale a /E:OFF y /R equivale a /C. Se omitirá cualquier otro tipo de modificador. Si se especifica /C o /K, lo que viene después de la línea de comando se ejecuta como línea de comando, siguiendo la lógica siguiente para procesar caracteres comillas ("): 1. Se conservan las comillas del comando si se cumplen todas las condiciones siguientes:

- no aparece el modificador /S - hay exactamente dos caracteres comillas - no hay caracteres especiales entre ambas comillas, siendo los caracteres especiales: &()@^| - hay uno o más espacios en blanco entre ambas comillas - la cadena entre ambas comillas es el nombre de un archivo ejecutable 2. En caso contrario, el comportamiento clásico es comprobar si el primer carácter es una comilla y de ser así, quitar ésta y también la última comilla de la línea de comandos, conservando el texto que venga después de ésta Si no se especificó /D en la línea de comandos, cuando CMD.EXE se inicie, buscará las variables del Registro REG_SZ/REG_EXPAND_SZ, y si alguna de ellas está presente, se ejecutarán en primer lugar. HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun y (o) HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun Las extensiones de comando están habilitadas de forma predeterminada. Puede deshabilitar las extensiones de una invocación particular usando el modificador /E:OFF. Puede habilitar o deshabilitar las extensiones de todas las invocaciones de CMD.EXE en una máquina o en una sesión de usuario estableciendo con REGEDT32.EXE los dos valores de REG_DWORD del registro siguientes: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\EnableExtensions y (o)

HKEY_CURRENT_USER\Software\Microsoft\Command Processor\EnableExtensions a 0x1 o 0x0. La configuración específica del usuario tiene preferencia respecto a la del equipo. Los modificadores de la línea de comando tienen prioridad sobre la configuración del registro Las extensiones de comando implican cambios y ampliaciones en los siguientes comandos: DEL o ERASE COLOR CD o CHDIR MD o MKDIR PROMPT PUSHD POPD SET SETLOCAL ENDLOCAL IF FOR CALL SHIFT GOTO START (también incluye cambios en la invocación de comandos externos) ASSOC FTYPE Para obtener detalles específicos, escriba nombredelcomando /?. La expansión de variables de entorno retardada NO está habilitada de manera predeterminada. Puede habilitar o deshabilitar la expansión de variables de entorno retardada para una llamada particular de CMD.EXE con los modificadores /V:ON o /V:OFF. Puede habilitar o deshabilitar la terminación para todas las llamadas de CMD.EXE en una sesión de inicio de usuario o equipo estableciendo con REGEDT32.EXE los dos valores de REG_DWORD del registro siguientes: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion y (o)

HKEY_CURRENT_USER\Software\Microsoft\Command Processor\DelayedExpansion a 0x1 ó 0x0. La configuración específica del usuario tiene prioridad sobre la configuración del equipo. Los modificadores de la línea de comandos tienen prioridad sobre la configuración del Registro. Si la expansión de variables de entorno retardada está habilitada, se puede utilizar el carácter de exclamación para sustituir el valor de la variable de entorno en tiempo de ejecución. La terminación de los nombres de Archivo y Directorio NO está habilitada de forma predeterminada. Se puede habilitar o deshabilitar la terminación de un nombre de archivo para una invocación particular de CMD.EXE con el modificador /F:ON o /F:OFF. Se puede habilitar o deshabilitar la terminación para todas las invocaciones de CMD.EXE en una máquina y/o el inicio de sesión del usuario estableciendo cualquiera de los dos siguientes valores REG_DWORD en el registro usando REGEDT32.EXE: HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\CompletionChar HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\PathCompletionChar y/o HKEY_CURRENT_USER\Software\Microsoft\Command Processor\CompletionChar HKEY_CURRENT_USER\Software\Microsoft\Command Processor\PathCompletionChar con el valor hex de un carácter de control para utilizarlo en una función particular (por ej. 0x4 es Ctrl-D y 0x6 es Ctrl-F). La configuración de usuario específica tiene precedencia sobre la configuración de la máquina.Los modificadores de la línea de comandos tiene precedencia sobre laconfiguración del registro. Si la terminación está habilitada con el modificador /F:ON, los dos caracteres de control usados son Ctrl-D para la terminación del nombre del directorio y

Ctrl-F para la terminación del nombre de archivo. Para deshabilitar una terminación de carácter determinada en el registro, utilice el valor del espacio en blanco (0x20), ya que no es un carácter de control válido. Se invoca la terminación cuando se escriben cualquiera de los dos caracteres de control. La función de terminación, desplaza el contenido de la ruta de acceso hacia la izquierda del cursor, le anexa un carácter comodín si no hay ninguno todavía presente y genera una lista de rutas de acceso que coincidan. Después muestra la primera ruta de acceso que coincida. Si no coincide ninguna ruta de acceso, emite un sonido y no muestra nada. Posteriormente, el presionar repetidamente el mismo carácter de control se desplazará a través de la lista de las rutas de acceso que coinciden. Si presiona la tecla Mayús con el carácter de control se moverá a través de la lista hacia atrás. Si se edita la línea de cualquier manera y presiona el carácter de control de nuevo, la lista de ruta de acceso guardada es anulada y se generará una nueva. Ocurrirá lo mismo si pasa de una terminación de nombre de archivo a uno de directorio. La única diferencia entre los dos caracteres de control es que la terminación del carácter del archivo coincide con ambos nombres del archivo y del directorio, mientras que la terminación del carácter del directorio sólo coincide con los nombres del directorio. Si la terminación del archivo es usada en cualquier construcción de comandos de directorio (CD, MD o RD) entonces se asume la terminación del directorio. El código de terminación trata adecuadamente con nombres de archivo que contienen espacios u otros caracteres especiales colocando comillas entre la ruta de acceso que coincide. También, si se hace una copia de seguridad, se llamará a una

terminación dentro de la misma línea, el texto a la derecha del cursor que fue llamado en el punto de la terminación es descartado. Los caracteres especiales que requieren comillas son: &()[]{}^=;!'+,`~

IF ERRORLEVEL Cada orden externa de ms-dos genera un código de salida a su término indicando si pudo realizarse satisfactoriamente. Generalmente un código de salida 0 indica que no hubo ningún problema y un código de salida superior hace referencia a diferentes errores. Muchos ficheros por lotes necesitan saber si la orden anterior cumplió su cometido correctamente: para ello utilizan la orden If errorlevel. Es muy importante recordar que la orden se ejecutará si el código de salida es igual o superior al especificado detrás de ERRORLEVEL. A modo de ejemplo tenemos a continuación los códigos de salida de Xcopy:

Código Significado 0 Los ficheros fueron copiados sin error. 1 No se encontraron ficheros para copiar. 2 El usuario presionó Ctrl+Pausa para suspender el proceso de Xcopy. 4 Ocurrió un error de inicio. No hay suficiente memoria o espacio en el disco, se introdujo un nombre de unidad no válida o se utilizó una sintaxis incorrecta en la línea de órdenes. 5 Ocurrió un error de escritura de disco.

Vamos a crear un fichero por lotes para copiar los ficheros de la unidad A: a la B: e informe del resultado de la copia. @echo off rem Programa: COPIA-AB.BAT

xcopy a:\ b:\ if errorlevel 1 goto Error if errorlevel 0 echo ¡La copia fue correcta! goto Final :Error echo Se produjo un error durante la copia :Final En primer lugar, Xcopy intenta realizar la copia de ficheros y devolverá un código de salida. Si se ha producido algún error el código será 1 o superior y entonces, el programa se desvía hasta la etiqueta :Error, muestra el mensaje y finaliza. Si la copia fue satisfactoria, el código de salida es 0. La segunda línea If mostrará el mensaje de éxito, saltando después a la etiqueta :Final y como no hay más líneas, termina el proceso. En muchas ocasiones puede ser fuente de complicaciones que If errorlevel número se cumpla si el número es igual o mayor. Para cumplirse exclusivamente si el código de salida es 5 -por ejemplopodemos usar lo siguiente: if errorlevel 5 if not errorlevel 6 dir Esta compleja línea se traduce así: «Si el código de salida es 5 o superior pero inferior a 6 ejecutar Dir», es decir, si el código es 5 ejecutar Dir. La orden CHOICE Permite escoger una opción entre varias y, dependiendo de la opción elegida, devuelve un código de salida. Su sintaxis es: CHOICE [mensaje] [/C:opciones] [/N] [/S] [/T:opción,segundos]

/C:opciones Especifica las opciones posibles. Si el usuario pulsa la primera de las opciones, Choice devolverá un código de salida 1; si pulsa la segunda opción, Choice devuelve el código 2 y así sucesivamente. Si no se especifica este parámetro se asumen las opciones por defecto (SN). /N No muestra las opciones admitidas detrás del mensaje. /S Hace distinción entre mayúsculas y minúsculas. Si no se especifica este parámetro se toman como la misma opción. /T:opción,segs Toma la opción indicada si no se pulsa ninguna otra tecla en los segundos especificados. mensaje Contiene el mensaje mostrado al usuario pidiendo que introduzca una de las opciones admitidas.

El programa DEMO.BAT podemos mejorarlo sensiblemente si cambiamos las órdenes Pause por órdenes Choice. @echo off rem Programa: DEMOB.BAT echo ******************************************** echo ** Este programa copia todos los ficheros ** echo ** de la unidad A: al directorio actual ** echo ******************************************** choice ¿Desea continuar? if errorlevel 2 goto Final :Proceso copy a:\ . choice Para continuar con otro disquete pulse C y para finalizar, F /C:FC if errorlevel 2 goto proceso :Final En la primera orden Choice se toman las opciones por defecto S y N. `S' corresponde a un código de salida 1 y `N' a un código 2. En la segunda orden Choice se toman las opciones F y C. `F' corresponde a un código 1 y `C' a un código 2. Con la orden Choice y de una forma muy sencilla podemos crear menús con diferentes opciones: @echo off rem Programa: UTIL.BAT :Menu cls echo UTILIDADES DE MS-DOS echo -------------------echo. echo A. Anti-Virus echo B. Backup echo D. Defragmentar echo E. Editor echo S. Salir echo. choice ¿Qué utilidad desea comenzar? /c:abdes /n /t:s,15 if errorlevel 5 goto Salir if errorlevel 4 goto Editor if errorlevel 3 goto Defrag if errorlevel 2 goto Backup if errorlevel 1 goto Anti if errorlevel 0 goto Menu :Anti MSAV goto Menu

:Backup MSBACKUP goto Menu :Defrag DEFRAG goto Menu :Editor EDIT goto Menu :Salir echo. Observe la orden Choice: el modificador /C indica las opciones admitidas. Si se pulsa la `A' se generará un código de salida 1 y así sucesivamente hasta la `S' que corresponde a un código 5. Gracias al modificador /N Choice no muestra las teclas admitidas detrás del mensaje. El modificador /T toma como opción por defecto la `S' si pasan 15 segundos sin pulsar ninguna tecla. Observe, asimismo, cómo se ha comenzado en las líneas If por el errorlevel más alto: así se evitan conflictos. El código de salida 0 se obtiene si el usuario responde con Ctrl+Pausa al mensaje de Choice Ejemplo de un proceso batch Lo que voy a realizar aqui, es un proceso batch que os permita entender mejor la teoria que explique en la entrada de "Curso basico de MS-DOS". Este proceso lo que hace es crear un menu principal que contiene los siguientes puntos: • • •

Aplicaciones Utilidades Fin

Dentro de estos hay submenus que llevan a ordenes como la de copiar un archivo etc... Este es el proceso: @echo off

echo MENU PRINCIPAL echo 1-Aplicaciones echo 2-Utilidades echo 3-Fin echo -------------------------------------choice /c 123 /m "Elija una opcion" @if errorlevel 3 goto :fin @if errorlevel 2 goto :utilidades @if errorlevel 1 goto :aplicaciones

:aplicaciones cls echo A.-Memoria echo B.-Fecha echo C.-Menu principal choice /c ABC /m "Elija una opcion" cls @if errorlevel 3 Examen.bat @if errorlevel 2 goto :fecha @if errorlevel 1 goto :memoria :memoria cls ver pause goto :menu :fecha cls date 01-01-2011 date /t pause goto :menu :utilidades cls echo A.-util1 echo B.-util2 echo C.-copiar echo D.-Menu principal choice /c ABCD /m "Elija una opcion" @if errorlevel 4 goto :menu @if errorlevel 3 goto :copiar @if errorlevel 2 goto :util2 @if errorlevel 1 goto :util1 :util1 cls dir c:\utilidades /a:a pause goto :menu :util2

cls dir c:\ "asi1.*" pause goto :menu :copiar cls copy c:\prueba.txt c:\asi1\texto1.txt pause goto :menu :fin exit FINAL DEL PROCESO