I have a batch file that's calling the same executable over and over with different parameters. How do I make it terminate immediately if one of the calls returns an error code of any level?
Basically, I want the equivalent of MSBuild's ContinueOnError=false
.
This question is related to
batch-file
Add || goto :label
to each line, and then define a :label
.
For example, create this .cmd file:
@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%
Here is a polyglot program for BASH and Windows CMD that runs a series of commands and quits out if any of them fail:
#!/bin/bash 2> nul
:; set -o errexit
:; function goto() { return $?; }
command 1 || goto :error
command 2 || goto :error
command 3 || goto :error
:; exit 0
exit /b 0
:error
exit /b %errorlevel%
I have used this type of thing in the past for a multiple platform continuous integration script.
@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
The shortest:
command || exit /b
If you need, you can set the exit code:
command || exit /b 666
And you can also log:
command || echo ERROR && exit /b
I prefer the OR form of command, as I find them the most readable (as
opposed to having an if after each command). However, the naive way of
doing this, command || exit /b %ERRORLEVEL%
is wrong.
This is because batch expands variables when a line is first read, rather
than when they are being used. This means that if the command
in the line
above fails, the batch file exits properly, but it exits with return code 0,
because that is what the value of %ERRORLEVEL%
was at the start of the
line. Obviously, this is undesirable in our script, so we have to enable
delayed expansion, like so:
SETLOCAL EnableDelayedExpansion
command-1 || exit /b !ERRORLEVEL!
command-2 || exit /b !ERRORLEVEL!
command-3 || exit /b !ERRORLEVEL!
command-4 || exit /b !ERRORLEVEL!
This snippet will execute commands 1-4, and if any of them fails, it will exit with the same exit code as the failing command did.
No matter how I tried, the errorlevel always stays 0 even when msbuild failed. So I built my workaround:
Build Project and save log to Build.log
SET Build_Opt=/flp:summary;logfile=Build.log;append=true
msbuild "myproj.csproj" /t:rebuild /p:Configuration=release /fl %Build_Opt%
search for "0 Error" string in build log, set the result to var
FOR /F "tokens=* USEBACKQ" %%F IN (`find /c /i "0 Error" Build.log`) DO (
SET var=%%F
)
echo %var%
get the last character, which indicates how many lines contains the search string
set result=%var:~-1%
echo "%result%"
if string not found, then error > 0, build failed
if "%result%"=="0" ( echo "build failed" )
That solution was inspired by Mechaflash's post at How to set commands output as a variable in a batch file
We cannot always depend on ERRORLEVEL, because many times external programs or batch scripts do not return exit codes.
In that case we can use generic checks for failures like this:
IF EXIST %outfile% (DEL /F %outfile%)
CALL some_script.bat -o %outfile%
IF NOT EXIST %outfile% (ECHO ERROR & EXIT /b)
And if the program outputs something to console, we can check it also.
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)
One minor update, you should change the checks for "if errorlevel 1" to the following...
IF %ERRORLEVEL% NEQ 0
This is because on XP you can get negative numbers as errors. 0 = no problems, anything else is a problem.
And keep in mind the way that DOS handles the "IF ERRORLEVEL" tests. It will return true if the number you are checking for is that number or higher so if you are looking for specific error numbers you need to start with 255 and work down.
Source: Stackoverflow.com