¿Cómo puedo hacer que un archivo por lotes termine al encontrar un error?


Tengo un archivo por lotes que está llamando al mismo ejecutable una y otra vez con diferentes parámetros. ¿Cómo puedo hacer que termine inmediatamente si una de las llamadas devuelve un código de error de cualquier nivel?

Básicamente, quiero el equivalente de ContinueOnError=false de MSBuild.

 232
Author: Nakilon, 2009-04-09

10 answers

Compruebe el errorlevel en una instrucción if, y luego exit /b (salga solo del archivo b atch, no de todo el cmd.proceso exe) para valores distintos de 0.

same-executable-over-and-over.exe /with different "parameters"
if %errorlevel% neq 0 exit /b %errorlevel%

Si desea que el valor del nivel de error se propague fuera de su archivo por lotes

if %errorlevel% neq 0 exit /b %errorlevel%

Pero si esto está dentro de un for se pone un poco complicado. Necesitarás algo más como:

setlocal enabledelayedexpansion
for %%f in (C:\Windows\*) do (
    same-executable-over-and-over.exe /with different "parameters"
    if !errorlevel! neq 0 exit /b !errorlevel!
)

Edit: Tienes que comprobar el error después de cada comando. No hay un tipo de construcción global "on error goto" en cmd. exe / command.com batch. También he actualizado mi código por CodeMonkey , aunque nunca he encontrado un errorlevel negativo en ninguno de mis lotes de hacking en XP o Vista.

 245
Author: system PAUSE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:14

Agregue || goto :label a cada línea, y luego defina un :label.

Por ejemplo, cree esto .archivo cmd:

@echo off

echo Starting very complicated batch file...
ping -invalid-arg || goto :error
echo OH noes, this shouldn't have succeeded.
goto :EOF

:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

Ver también pregunta sobre cómo salir de la subrutina del archivo por lotes.

 214
Author: Fowl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-20 10:18:19

El más corto:

command || exit /b

Si lo necesita, puede establecer el código de salida:

command || exit /b 666

Y también puedes registrar:

command || echo ERROR && exit /b
 64
Author: Benoit Blanchon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-20 15:26:00

Una actualización menor, debe cambiar las comprobaciones de "if errorlevel 1" a lo siguiente...

IF %ERRORLEVEL% NEQ 0 

Esto se debe a que en XP puede obtener números negativos como errores. 0 = no hay problemas, cualquier otra cosa es un problema.

Y tenga en cuenta la forma en que DOS maneja las pruebas "IF ERRORLEVEL". Devolverá true si el número que está buscando es ese número o mayor, por lo que si está buscando números de error específicos, debe comenzar con 255 y trabajar hacia abajo.

 24
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-27 14:34:05

Aquí hay un programa políglota para BASH y Windows CMD que ejecuta una serie de comandos y se cierra si alguno de ellos falla:

#!/bin/bash 2> nul

:; set -o errexit
:; function goto() { return $?; }

command 1 || goto :error

command 2 || goto :error

command 3 || goto :error

:error

:; exit 0
exit /b 0

:error
exit /b %errorlevel%

He utilizado este tipo de cosas en el pasado para una plataforma múltiple integración continua script.

 8
Author: Erik Aronesty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-18 14:55:15

Prefiero la forma de comando OR, ya que los encuentro más legibles (como opuesto a tener un si después de cada comando). Sin embargo, la manera ingenua de hacer esto, command || exit /b %ERRORLEVEL%es incorrecto.

Esto se debe a que batch expande las variables cuando se lee una línea por primera vez, en lugar de que cuando se están utilizando. Esto significa que si el command en la línea arriba falla, el archivo por lotes sale correctamente, pero sale con el código de retorno 0, porque eso es lo que el valor de %ERRORLEVEL% era al comienzo de la alinear. Obviamente, esto es indeseable en nuestro script, por lo que tenemos que habilitar expansión retardada, así:

SETLOCAL EnableDelayedExpansion

command-1 || exit /b !ERRORLEVEL!
command-2 || exit /b !ERRORLEVEL!
command-3 || exit /b !ERRORLEVEL!
command-4 || exit /b !ERRORLEVEL!

Este fragmento ejecutará los comandos 1-4, y si alguno de ellos falla, salga con el mismo código de salida que el comando fallido.

 3
Author: Xarn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-17 14:20:18

No siempre podemos depender de ERRORLEVEL, porque muchas veces los programas externos o los scripts por lotes no devuelven los códigos de salida.

En ese caso podemos usar comprobaciones genéricas para fallos como este:

IF EXIST %outfile% (DEL /F %outfile%)
CALL some_script.bat -o %outfile%
IF NOT EXIST %outfile%  (ECHO ERROR & EXIT /b)

Y si el programa da salida a algo para consolar, podemos comprobarlo también.

some_program.exe 2>&1 | FIND "error message here" && (ECHO ERROR & EXIT /b)
some_program.exe 2>&1 | FIND "Done processing." || (ECHO ERROR & EXIT /b)
 2
Author: Amr Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-26 06:11:44

No importa cómo lo intente, el nivel de error siempre permanece 0 incluso cuando msbuild falló. Así que construí mi solución:

Compilar proyecto y guardar registro para compilar.log

SET Build_Opt=/flp:summary;logfile=Build.log;append=true

msbuild "myproj.csproj" /t:rebuild /p:Configuration=release /fl %Build_Opt%

Busque la cadena "0 Error" en el registro de compilación, establezca el resultado en var

FOR /F "tokens=* USEBACKQ" %%F IN (`find /c /i "0 Error" Build.log`) DO (
    SET var=%%F
)
echo %var%

Obtiene el último carácter, que indica cuántas líneas contiene la cadena de búsqueda

set result=%var:~-1%

echo "%result%"

Si string no se encuentra, entonces error > 0, build failed

if "%result%"=="0" ( echo "build failed" )

Esa solución fue inspirada por el post de Mechaflash en Cómo establecer la salida de comandos como una variable en un archivo por lotes

Y https://ss64.com/nt/syntax-substring.html

 1
Author: E.Seven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-05 15:13:22

Simplemente use ERRORLEVEL para lograr el resultado que desea. Hay dos variables en el comando ERRORLEVELque determinarían si un proceso falló o tuvo éxito, estas variables son ERRORLEVEL 0 y ERRORLEVEL 1 (1 para fail, 0 para pass). Aquí hay un ejemplo de cómo se usaría esto en un archivo por lotes:

echo off
cls
ping localhost 
errorlevel 0 goto :good
errorlevel 1 goto :bad

:good
cls
echo Good!
echo[
pause
exit

:bad
cls
echo Bad!
echo[
pause
exit

Aquí hay un enlace con más información si lo necesita: Errorlevels

 0
Author: PryroTech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-25 02:43:16
@echo off

set startbuild=%TIME%

C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe c:\link.xml /flp1:logfile=c:\link\errors.log;errorsonly /flp2:logfile=c:\link\warnings.log;warningsonly || goto :error

copy c:\app_offline.htm "\\lawpccnweb01\d$\websites\OperationsLinkWeb\app_offline.htm"

del \\lawpccnweb01\d$\websites\OperationsLinkWeb\bin\ /Q

echo Start Copy: %TIME%

set copystart=%TIME%

xcopy C:\link\_PublishedWebsites\OperationsLink \\lawpccnweb01\d$\websites\OperationsLinkWeb\ /s /y /d

del \\lawpccnweb01\d$\websites\OperationsLinkWeb\app_offline.htm

echo Started Build: %startbuild%
echo Started Copy: %copystart%
echo Finished Copy: %TIME%

c:\link\warnings.log

:error

c:\link\errors.log
 -2
Author: Demican,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-05 23:50:41