1

I would like to ask you if you could hint me to a somehow more elegant solution (than the one provided at the end of this post) to this problem: I want to run a batch script which, if (at least) one of its instructions fails, will continue running the other instructions, but will return an errorlevel indicating a failure (say, 1).

One solution which I tested (and works) is the following:

set instructionfailed=0
**INSTRUCTION THAT WILL FAIL (ex. copy a a)**
if %errorlevel% == 1 set instructionfailed=1
**INSTRUCTION THAT WILL SUCCEED (ex.(supposing abcdefg does not exist) mkdir abcdefg) **
if %errorlevel% == 1 set instructionfailed=1
exit /b %instructionfailed%

EDIT: I have actually read (here, for example) that maybe I should use ERRORLEVEL instead of %errorcode%, but the code I have to integrate this with also seems to use %errorcode%.

PhantomR
  • 605
  • 4
  • 16
  • 1
    Why are you talking about **ERROCODE**. That variable does not exist in your code nor is it a system variable. Personally I don't think it matters if you use `if %errorlevel% == 1 set instructionfailed=1` or `if errorlevel 1 set instructionfailed=1` – Squashman Dec 14 '17 at 19:29
  • It was a mistake :), I was thinking about ERRORCODE. Thank you for pointing it out. – PhantomR Dec 15 '17 at 09:21
  • 1
    Remember: `%errorlevel%` of `0` is (by convention) "success", "failed" isn't neccessarily `1`, but actually is "Not `0`" (example: "no such command" gives an `%errorlevel%` of `9009`, [fc](https://ss64.com/nt/fc.html) may give `-1`, `1`, or `2` for "failed"). So you may want to use `if %errorlevel% neq 0` instead of `if %errorlevel% == 1`. – Stephan Dec 15 '17 at 11:40
  • 1
    Read the Microsoft support article [Testing for a Specific Error Level in Batch Files](https://support.microsoft.com/en-us/kb/69576). All you need after each **INSTRUCTION** is the line `if errorlevel 1 set instructionfailed=1`. – Mofi Dec 15 '17 at 12:25

1 Answers1

1

There is one exceptionally simple technique that may work, depending on which commands are executed, and another slightly more complex technique that will always work.

1) Simple solution that may or may not work, depending on the commands

Some internal commands only set the ERRORLEVEL if and only if there was an error, and some always set the ERRORLEVEL upon success or error. External commands always set the ERRORLEVEL.

So if all of your commands are internal commands that do not clear the ERRORLEVEL upon success, then you can simply clear the ERRORLEVEL at the start, and then run each command in succession. The ERRORLEVEL will only be non-zero (indicating an error) if any one of the commands failed. You can simply issue EXIT /B at the end, and the current ERRORLEVEL will be returned.

An arcane but quick way to clear the ERRORLEVEL to 0 at the start is to use (call ) - the trailing space is critical.

(call )
internalCommand1
internalCommand2
...
internalCommandN
exit /b

A list of internal commands that can work with this solution may be found at Which cmd.exe internal commands clear the ERRORLEVEL to 0 upon success?. Again, for this solution to work, you want the internal commands that do not clear the ERRORLEVEL upon success.

2) Slightly more complex solution that always works

Just as with your current solution, you set your own error variable to 0 at the start, and conditionally set it to non zero upon error after each command. But instead of using if errorlevel 1 or if %errorlevel% neq 0, you can use the conditional || command concatenation operator, which only executes the command if the preceding one failed.

set "err=0"
anyCommand1 || set "err=1"
anyCommand2 || set "err=1"
...
anyCommandN || set "err=1"
exit /b %err%
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390