18

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jordan Evens
  • 405
  • 1
  • 4
  • 14
  • I have never seen those operators used in batch files before. I don't think you're doing what you think you're doing. Edit: and I can't find any documentation about it, so I'm surprised you haven't seen any syntax errors. – Mike Caron Jan 08 '11 at 07:27
  • 3
    The usage of these operators is detailed here: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true – Jordan Evens Jan 08 '11 at 07:49
  • @JordanEvens I get `the page you requested cannot be found` (but three upvotes suggest, it's just me...) Another description is on [SS64](https://ss64.com/nt/syntax-conditional.html) – Stephan Aug 22 '18 at 13:55
  • Can't find a replacement right away on the microsoft site, but the wayback machine seems to have a copy of the original: https://web.archive.org/web/20170220015700/http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true – Jordan Evens Aug 22 '18 at 17:11

4 Answers4

14

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.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • 1
    Although it's a bit weird to use this for exiting, it provides the expected behaviour when other things call the batch so it makes the most sense to use this instead of modifying everything else to use calls. – Jordan Evens Jan 09 '11 at 00:01
  • 4
    I was confused for a bit, so this is just a note for others that you literally need that to be the last line of the file. It won't actually exit the batch, just set the error code. Calling `EXIT /B %ERRORLEVEL%` directly after it doesn't always seem to work either. The only reliable method I found was to use `IF ERRORLEVEL 1 goto :end` and have a label `:end` just before the last line with `%COMSPEC% /C EXIT %ERRORLEVEL%>NUL` – Jordan Evens Jan 10 '11 at 14:34
  • Could this issue be related to a [problem I encountered recently](http://stackoverflow.com/questions/14418960/dos-inline-if-test-for-errorlevel-without-use-of-delayed-expansion)? – user66001 Jan 19 '13 at 21:16
12

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.

marapet
  • 54,856
  • 12
  • 170
  • 184
  • 1
    Call has also an effect for this: set var=%%var%%call call call echo %var% – jeb Jan 08 '11 at 23:31
  • 1
    CALL command was there to address a historical mistake in the DOS ages: the old COMMAND.COM interpreter considers batch file command be launched differently than external programs (.com or .exe). For batch file command, the shell stops the batch file it's running and loads the new batch. (Think of this as similar to `exec foo.sh` in Unix shell - the old script halts and launches new one.) To address the cases where the users/scripts want to continue execution after new script finishes, CALL command was introduced. The peculiar behavior of batch file command remains for compatibility. – Explorer09 Apr 25 '17 at 14:52
  • The link is broken. – Peter Mortensen Aug 22 '18 at 15:55
0

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • there's no `start` command and `%errorlevel%` in DOS. [Windows cmd and MS-DOS are very different](https://superuser.com/q/451432/241386) – phuclv Aug 22 '18 at 15:59
0

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131