Marcus Leon
Marcus Leon

Reputation: 56679

DOS Batch script return code not being returned to caller

We have a file1.cmd calling file2.cmd calling file3.cmd.

file3.cmd returns a failure as: exit /b 1

But in file2.cmd we seem to "lose" this failure code. The %ERRORLEVEL% variable is being listed as 0 instead of 1.

Any ideas?

Upvotes: 0

Views: 699

Answers (1)

MC ND
MC ND

Reputation: 70933

Usual problems that can be found:

Setting the errorlevel variable to a value

set errorlevel=0
echo test | find "x" > nul 2>nul
echo %errorlevel%

Here the errorlevel will be set (the find operation has failed) but the value echoed to console will be 0. errorlevel is a dynamic variable and setting a value to it blocks the access to the dynamic value. errorlevel value should not be set with the set command.

If it is necessary to set errorlevel you can

  • When leaving the running batch: exit n or exit /b n
  • Inside the running batch, without leaving it: cmd /c exit n

in both cases with n the numeric value to set in the errorlevel

To clear the errorlevel you can use: ver>nul

Variable expansion

if 1==1 (
    echo test | find "x" > nul 2>nul
    if %errorlevel%==1 echo failed
)

When the batch parser reaches a line or a block of lines (lines enclosed in parenthesis), it replaces all the read operations on variables with the value inside the variable before execute the line/block. So, if a variable changes its value inside the line/block, the new value can no be retrieved from inside the same line/block. The read operation does not exist, it was replaced with the initial value.

Delayed expansion can be enabled, allowing to change (where needed) the syntax from %var% to !var!, indicating to the parser that the read operation must be delayed until the command executes

setlocal enabledelayedexpansion
if 1==1 (
    echo test | find "x" > nul 2>nul
    if !errorlevel!==1 echo failed
)

But for any of the two previous cases, there is an alternative. The batch language includes a construct to test for errorlevel that is not affected by assigned values or variable expansion

if errorlevel n .....

This construct will be evaluated to true for any errorlevel greater or equal to n. For this reason, when using this construct and testing for different error levels, it is necessary to test for errorlevel from greater to lower values

if errorlevel 3 (
    ....
) else if errorlevel 2 (
    ....
) else if errorlevel 1 ( 
    ....
) else (
  ....
)

In the cases where the only check is if errorlevel is set or not, this construct can be abreviated using conditional execution

command && ( .... ) || ( .... )

where the commands after the && are executed when the errorlevel is not set, and the commands after || are executed when the errorlevel is set

Upvotes: 1

Related Questions