Saltar al contenido

Diferencia entre “|| exit / b” y “|| exit / b! Errorlevel!”

Solución:

Soluciones alternativas:

  • Llame a su archivo por lotes a través de cmd /c call, en cuyo caso el || exit /b solución sin un código de salida explícito funciona como se esperaba.

    • cmd /c call .test.bat

    • Utilizando cmd /c call rutinariamente para llamar archivos por lotes desde el exterior cmd.exe es aconsejable, como incluso archivos por lotes sin exit De lo contrario, las llamadas pueden comportarse de forma inesperada; consulte esta respuesta.

  • Alternativamente, pero solo si su archivo por lotes nunca necesita ser llamado de otro archivo por lotes a qué control se debe devolver y si nunca necesita ser parte de un cmd /c multi-comando línea de comando donde no es el último mando[1] – puedes usar || exit en lugar de || exit /b – esto sale de la ejecución cmd.exe proceso como un todo, instantáneamente, pero el código de salida (nivel de error) es luego informado de manera confiable (al menos en el contexto de un <command> || exit declaración) también con directo invocación desde fuera cmd.exe, tal como & .test.bat (o, en este simple caso, simplemente .test.bat) de PowerShell.

Mientras combina setlocal EnableDelayedExpansion con exit /b !ERRORLEVEL! también funciona, debido al uso de un explícito código de salida: obviamente es más engorroso y puede tener efectos secundarios, en particular, eliminar silenciosamente ! caracteres de comandos como echo hi! (aunque es posible minimizar ese problema colocando el setlocal EnableDelayedExpansion llamar a la línea justo antes de un exit /b llamada, que requeriría la duplicación si hay varios puntos de salida).


cmd.exeEl comportamiento es desafortunado en este caso, pero no se puede evitar.

Al llamar a un archivo por lotes desde fuera cmd.exe:

  • exit /bsin un argumento de código de salida (nivel de error): solo establece el cmd.exe procesar código de salida como se esperaba, es decir, al código de salida del comando ejecutado más recientemente en el archivo por lotes – si llama al archivo por lotes con call, es decir, como cmd /c call <batch-file>

    • Sin call, un argumento sin argumentos exit /b llamar desde un archivo por lotes es reflejado en el %ERRORLEVEL% variable intra-cmd.exe-sesión, pero eso no se traduce en cmd.exe‘s proceso código de salida, que por defecto es 0.[1]

    • Con call, sin argumentos exit /b lo hace correctamente configurado cmd.execódigo de salida, incluso en un <command> || exit /b declaración, en cuyo caso <command>El código de salida se retransmite, según lo previsto.

  • exit /b <code>, es decir, pasar un código de salida <code> explícitamente, siempre obras[2], es decir call es entonces no necesario.

  • Esta distinción es una Inconsistencia oscura que podría justificarse como un error.; La útil respuesta de Jeb tiene un código de muestra que demuestra el comportamiento.


[1] Con cmd /c, puedes pasar múltiple declaraciones para la ejecución, y es el último declaración que determina el cmd.exe código de salida del proceso. P.ej, cmd /c "ver & dir nosuch" informa el código de salida 1, porque el elemento del sistema de archivos inexistente nosuch causado dir para establecer el nivel de error en 1, independientemente de si el comando anterior (ver) tuvo éxito. La inconsistencia es que, para un archivo por lotes llamado test.bat que sale con exit /b sin un argumento de código de salida explícito, cmd /c test.bat siempre informa 0, mientras que cmd /c call test.bat informa correctamente el código de salida del última declaración ejecutada antes de que saliera el archivo por lotes.

[2] El código de salida puede especificarse literalmente o mediante una variable, pero el problema es que, debido a cmd.exeexpansión variable inicial – <command> || exit /b %ERRORLEVEL% lo hace no funciona según lo previsto, porque %ERRORLEVEL% en ese punto se expande al nivel de error previo a esta declaración, no a la establecida por <command>; esta es la razón por demorado expansión, a través de haber corrido setlocal enabledelayedexpansion o haber invocado el cmd.exe con el /V opción, es necesaria en este caso: <command> || exit /b !ERRORLEVEL!

Hay una diferencia entre exit /b y exit /b <code>.
Como dice mklement0, la diferencia se hace visible al llamar a un archivo por lotes con o sin CALL

En mis pruebas, usé (call) para forzar el nivel de error a 1.

test1.bat

@echo off
(call)
exit /b

test2.bat

@echo off
(call)
exit /b %errorlevel%

Probando con prueba-todo.bat:

cmd /c "test1.bat" & call echo      Test1 %%errorlevel%%
cmd /c "call test1.bat" & call echo call Test1 %%errorlevel%%
cmd /c "test2.bat" & call echo      Test2 %%errorlevel%%
cmd /c "call test2.bat" & call echo call Test2 %%errorlevel%%

Producción:

     Test1 0  
call Test1 1  
     Test2 1  
call Test2 1

Para obtener un nivel de error siempre confiable, debe usar la forma implícita de exit /b <code>.
En caso de utilizar la construcción <command> || exit /b !errorlevel! la expansión retardada es necesaria o la forma

<command> || call exit /b %%errorlevel%%

Otra solución

<command> || call :exit
...

:exit
(
   (goto) 2>nul
   exit /b
)    

Esto usa el manejo de excepciones por lotes

¿Windows admite el manejo de excepciones por lotes?

Veamos los tres posibles escenarios:

cmd /c "exit 99" || exit /b

devoluciones 0 porque cmd /c "exit 99" ejecutado correctamente

cmd /c "exit 99" || exit /b !errorlevel!

devoluciones 99 porque cmd /c "exit 99" colocar errorlevel a 99 y estamos devolviendo el nivel de error que resultados de ejecutar cmd /c "exit 99"

cmd /c "exit 99" || exit /b %errorlevel%

devoluciones ? – nivel de error como estaba cuando el cmd /c "exit 99" La línea se analizó ya que en ese momento se evaluó ‘% errorlevel%.

Si delayedexpansion era no , entonces la única diferencia es que el !errorlevel! El escenario intenta asignar una cadena al nivel de error, que probablemente no funcionará muy bien.

En cuanto a Powershell, es un caso de esquina en una carretera menos transitada. Un escenario que no se probó a fondo como los diseñadores esperaban ejecutar .exes, etc. utilizando esta función. Sin duda, incluso si se informa, no se solucionaría, ya que hay una solución alternativa, incluso si no está bien expuesto.

Este es, creo, el escenario de falla a falla: una instalación que se supone que funciona porque rara vez se cumplen las condiciones adecuadas para hacerla fallar.

Del mismo modo,

echo %%%%b

es ambiguo. ¿Significa echo el literal %%b o para echo % prefijado al contenido de la metavariable b? (Respuesta: este último). No se encuentra exactamente todos los días. ¿Qué posibilidades hay de que se resuelva la ambigüedad, alguna vez? Ni siquiera podemos conseguir /u implementado en el date comando para que entregue la fecha en un formato universal que resolvería la gran mayoría de las preguntas orientadas a la fecha publicadas en el batch etiqueta. En cuanto a la posibilidad de un interruptor para permitir date para entregar días-desde-alguna-época-fecha – ni siquiera me he molestado en sugerirlo desde entonces, a pesar de invitar sugerencias para cmd modificaciones, absolutamente nada Se ha realizado sobre las instalaciones ofrecidas, solo cambios en la interfaz de usuario. Jugando con todas las cosas brillantes mientras los viejos fieles languidecen en el fondo de un archivador cerrado y metido en un baño en desuso con un letrero en la puerta que dice “Cuidado con el leopardo”.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *