¿Puedo tener un bloque IF en un archivo por lotes de DOS?

97

En un archivo por lotes de DOS solo podemos tener 1 línea si el cuerpo de la declaración? Creo que encontré un lugar que podría usar ()para un bloque if como el que se {}usa en los lenguajes de programación tipo C, pero no está ejecutando las declaraciones cuando intento esto. Tampoco hay mensaje de error. Este es mi código:

if %GPMANAGER_FOUND%==true(echo GP Manager is up
goto Continue7
)
echo GP Manager is down
:Continue7

Curiosamente, ni "GP Manager está activo" ni "GP Manager está inactivo" se imprimen cuando ejecuto el archivo por lotes.

Hugh Darling
fuente
Tal vez esto podría ayudar: commandwindows.com/batchfiles-branching.htm
esaj
Sí, eso ayuda. DOS apesta. ¿Si quiero usar varias declaraciones en if o si no tengo que usar && entre declaraciones? ¿O hay una forma más elegante?
Hugh Darling

Respuestas:

140

De hecho, puede crear un bloque de declaraciones para ejecutar después de un condicional. Pero tienes la sintaxis incorrecta. Los paréntesis deben usarse exactamente como se muestra:

if <statement> (
    do something
) else (
    do something else
)

Sin embargo, no creo que exista una sintaxis incorporada para las else-ifdeclaraciones. Desafortunadamente, necesitará crear bloques anidados de ifdeclaraciones para manejar eso.


En segundo lugar, esa %GPMANAGER_FOUND% == trueprueba me parece muy sospechosa. No sé en qué está configurada la variable de entorno o cómo la está configurando, pero dudo mucho que el código que ha mostrado produzca el resultado que está buscando.


El siguiente código de muestra funciona bien para mí:

@echo off

if ERRORLEVEL == 0 (
    echo GP Manager is up
    goto Continue7
)
echo GP Manager is down
:Continue7

Tenga en cuenta algunos detalles específicos sobre mi código de muestra:

  • El espacio agregado entre el final de la declaración condicional y el paréntesis de apertura.
  • Estoy configurando @echo offpara evitar ver todas las declaraciones impresas en la consola a medida que se ejecutan y, en su lugar, solo veo el resultado de las que comienzan específicamente echo.
  • Estoy usando la ERRORLEVELvariable incorporada solo como prueba. Leer más aquí
Cody Grey
fuente
1
Es mejor usarlo si% ERRORLEVEL% == 0, ya que la otra variante siempre es verdadera, porque SI ERRORLEVEL <N> es verdadero, si el nivel de error es igual o mayor <N>, los "==" se ignoran en este caso
jeb
@jeb: Creo que quizás no entendiste. Usar ERRORLEVELno es la respuesta a su problema. Simplemente estaba publicando un ejemplo de la sintaxis adecuada. Cualquiera de las formas es aceptable en este caso, como lo sería if 0 == 0o cualquier otra expresión trivial. Pero de hecho, asegúrese de comprender la diferencia entre la variable de entorno %ERRORLEVEL%y la interna ERRORLEVELdel procesador de comandos. Raymond Chen lo explica muy bien aquí en este blog .
Cody Gray
¿Puedes tener un ELSE IF?
xagyg
1
Agregando al comentario de @ mythofechelon, incluso un paréntesis de cierre aparentemente inofensivo en una declaración REM pondrá fin al bloque. por ejemplo, tirar REM This is a comment (or so I thought)al IFbloque te arruinará.
rkagerer
2
Tanto @mythofechelon como @rkagerer señalan problemas específicos de una regla general de que las cadenas deben estar entre comillas. Nunca debe codificar; IF %somevar%==example_string2 siempre debe ser código, de modo que el operando se resuelva en IF "value_of_somevar"=="example_string2"para evitar que los caracteres especiales en cualquier operando de cadena causen errores de sintaxis en la IFdeclaración. Los valores que establezca siempre deben hacerse como set "somevar=value_of_somevar" Esa sintaxis le permite escapar de los caracteres especiales en los valores de las variables, Nota eso no me refiero set somevar="value_of_somevar"
Saltar R
15

Lógicamente, la respuesta de Cody debería funcionar. Sin embargo, no creo que el símbolo del sistema maneje un bloque de código de manera lógica. Por mi vida, no puedo hacer que eso funcione correctamente con más de un comando dentro del bloque. En mi caso, las pruebas exhaustivas revelaron que todos los comandos dentro del bloque se almacenan en caché y se ejecutan simultáneamente al final del bloque. Por supuesto, esto no produce los resultados esperados. Aquí hay un ejemplo muy simplificado:

if %ERRORLEVEL%==0 (
set var1=blue
set var2=cheese
set var3=%var1%_%var2%
)

Esto debería proporcionar a var3 el siguiente valor:

blue_cheese

pero en cambio rinde:

_

porque los 3 comandos se almacenan en caché y se ejecutan simultáneamente al salir del bloque de código.

Pude superar este problema reescribiendo el bloque if para ejecutar solo un comando, goto, y agregando algunas etiquetas. Es torpe y no me gusta mucho, pero al menos funciona.

if %ERRORLEVEL%==0 goto :error0
goto :endif

:error0
set var1=blue
set var2=cheese
set var3=%var1%_%var2%

:endif
Mella
fuente
8
El uso de la expansión retardada debería funcionar: use:set var3=!var1!_!var2!
Dracorat
4

En lugar de este lío de goto, intente usar el ampersand & o el doble ampersand && (condicional al nivel de error 0) como separadores de comandos.

Arreglé un fragmento de script con este truco, para resumir, tengo tres archivos por lotes, uno que llama a los otros dos después de haber encontrado qué letras se han asignado las unidades de respaldo externas. Dejo el primer archivo en la unidad externa principal para que las llamadas a su rutina de respaldo funcionen bien, pero las llamadas al segundo requirieron un cambio de unidad activa. El siguiente código muestra cómo lo arreglé:

for %%b in (d e f g h i j k l m n o p q r s t u v w x y z) DO (
if exist "%%b:\Backup.cmd" %%b: & CALL "%%b:\Backup.cmd"
)
Luis
fuente
¿Por qué diablos es esto menos votado? Esto es exactamente lo que necesitaba.
ggb667
1
@ GCB667 - Para aclarar, @Louis "escribió una" respuesta "que no se relaciona con el problema de por qué la declaración IF no funcionaba para el póster original. Se relacionaba con una respuesta de" vinniejohnson "(que también omitió el problema de los carteles originales) .
Saltar R
1

Me encontré con este artículo en los resultados devueltos por una búsqueda relacionada con el comando IF en un archivo por lotes, y no pude resistir la oportunidad de corregir la idea errónea de que los bloques IF se limitan a comandos únicos. A continuación se muestra una parte de una secuencia de comandos de producción de Windows NT que se ejecuta a diario en la máquina en la que estoy redactando esta respuesta.

    if "%COPYTOOL%" equ "R" (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using RoboCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    %TOOLPATH% %SRCEPATH% %DESTPATH% /copyall %RCLOGSTR% /m /np /r:0 /tee
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Robocopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
) else (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using XCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    call %TOOLPATH%  "%USERPROFILE%\My Documents\Outlook Files\*" "%USERPROFILE%\My Documents\Outlook Files\_backups" /f /m /v /y
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Xcopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
)

Quizás los bloques de dos o más líneas se apliquen exclusivamente a las secuencias de comandos de Windows NT (archivos .CMD), porque una búsqueda en el directorio de secuencias de comandos de producción de una aplicación que está restringida a archivos por lotes de la vieja escuela (.BAT) reveló solo bloques de un comando . Dado que la aplicación se ha sometido a un mantenimiento prolongado (lo que significa que no participo activamente en su soporte), no puedo decir si eso se debe a que no necesitaba más de una línea o que no podía hacer que funcionaran.

Independientemente, si esto último es cierto, hay una solución sencilla; mueva las líneas múltiples a un archivo por lotes separado o una subrutina de archivo por lotes. Sé que este último funciona en ambos tipos de guiones.

David A. Gray
fuente
0

Quizás un poco tarde, pero espero que sea un infierno:

@echo off 

if %ERRORLEVEL% == 0 (
msg * 1st line WORKS FINE rem You can relpace msg * with any othe operation...
goto Continue1
)
:Continue1
If exist "C:\Python31" (
msg * 2nd line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue2
)
:Continue2
If exist "C:\Python31\Lib\site-packages\PyQt4" (  
msg * 3th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue3
)
:Continue3
msg * 4th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue4
)
:Continue4
msg * "Tutto a posto" rem You can relpace msg * with any othe operation...
pause
vinniejohnson
fuente