I'm trying to chain a series of .bat files using the EXIT /B X
command to return success or failure and &&
and ||
for conditional running of the next .bat (e.g. a.bat && b.bat
).
Regardless of whether I call EXIT /B 0
or anything else to end a.bat, a.bat && b.bat
will call b.bat afterward. My understanding is that EXIT /B 0
should set ERRORLEVEL=0
, which is success, so the &&
should continue. The counterpoint to this is that calling EXIT /B 1
should set ERRORLEVEL=1
which is failure, so the &&
should stop. What am I missing here?
Trivialized example:
For non-batch commands, acting as expected:
C:\> echo test|findstr test>NUL && echo yes
yes
C:\> echo test|findstr test>NUL || echo yes
C:\> echo test|findstr nope>NUL && echo yes
C:\> echo test|findstr nope>NUL || echo yes
yes
Using EXIT /B
always sees a.bat as successful:
C:\> echo @EXIT /B 0 > a.bat
C:\> a.bat && echo yes
yes
C:\> a.bat || echo yes
C:\> echo @EXIT /B 1 > a.bat
C:\> a.bat && echo yes
yes
C:\> a.bat || echo yes
How can I exit from a.bat so that a.bat && b.bat
and a.bat || b.bat
behave as expected?
All commands are run in cmd.exe on Windows XP SP3.
If you ask me, exit codes in batch files are broken for this exact reason, but there is a hacky workaround you can use. As the last line of your batch file, use:
@%COMSPEC% /C exit 1 >nul
Since this is an actual process that is started you get a real process exit code and && and || will work.
It works as it should when using call to execute batch scripts containing an exit statement:
C:\>echo @EXIT /B 1 > a.bat
C:\>call a.bat && echo yes
C:\>call a.bat || echo yes
yes
By the way, it says wrongly on Microsoft docs:
Call has no effect at the command prompt
when it is used outside of a script or batch
file.
If you use start /wait
you can also use this in a very simple Windows application (written in C#) called by DOS batch files like so:
static class Program
{
[STAThread]
static void Main(string[] args)
{
Environment.ExitCode = Convert.ToInt32(args[0]);
}
}
Then the application can be called by your DOS batch file and evaluate the result. i.e.
c:> start /wait SetRC 1
c:> if "%errorlevel%"=="1" goto abort
NOTE: the /wait
is not necessary in a batch file.
You could pass in the return code you want as an argument to your program.cs and get it out this way guaranteed.
I think you are getting Errorlevel=0
with because you are indeed executing a.bat (regardless of the return code).
You would fail the check if a.bat
did not exist. CALL
is the only way I know to pull in the environment from a.bat
.