Exit /b 0 does not set %errorlevel% to 0

9,484

You have not shown the entire script. The only possible explanation I am aware of is your code is within a larger parenthesized block of code, possibly part of a FOR loop or an IF condition.

%ERRORLEVEL% is expanded when the line is parsed, and the entire parenthesized block is parsed at the same time. So the ERRORLEVEL that you are seeing must have existed prior to the start of the outermost paranthesis.

You should use delayed expansion if you want to see a changing value within a code block.

Here is a simple demonstration:

@echo off
setlocal enableDelayedExpansion
set var=BEFORE
(
  set var=AFTER
  echo Normal expansion shows value before block started: %var%
  echo Delayed expansion shows the current value: !var!
)

-- OUTPUT --

Normal expansion shows value before block started: BEFORE
Delayed expansion shows the current value: AFTER
Share:
9,484

Related videos on Youtube

Arne Mertz
Author by

Arne Mertz

Updated on September 18, 2022

Comments

  • Arne Mertz
    Arne Mertz almost 2 years

    I have a weird behavior wrt setting errorlevel in a batch script to 0.

    I am calling a batch script a.bat on a Jenkins job, which in turn calls a second script b.cmd and evaluates the errorlevel after the call:

    :: b.cmd
    :: some stuff, but relevant is only this:
    @echo b errorlevel: %errorlevel%
    EXIT /B 0
    

    The "main" script:

    :: a.bat
    pushd %CD%
    cd..
    
    @echo a errorlevel: %errorlevel%
    
    set outputdir=".\some\exisiting\dir"
    :: (1)
    md %outpurdir%
    @echo a errorlevel: %errorlevel%
    
    :: (!)
    if "$somevar" = "FOO" ( 
      cd .\WhereBIs
    
      :: (2)
      call :seterr 0
      @echo a errorlevel: %errorlevel%
    
      :: (3)
      call b.cmd
    
      @if %errorlevel% neq 0 (
        @echo a errorlevel: %errorlevel%
        set errmsg=Error calling b
        goto error
      )
    
      :: more stuff
    )
    
    :error
    @echo %errmsg%
    popd
    :: (4)
    @echo a errorlevel: %errorlevel%
    @if %errorlevel% neq 0 exit %errorlevel%
    Exit /B 1
    
    :seterr
    exit /b %1
    

    (I borrowed the :seterr stuff from this question)

    What seems to happen when I run the Jenkins job:

    1. md returns and errorlevel is set to 1, because the directory already exists.
    2. the call to :seterr does not have the expected effect, errorlevel remains 1
    3. the call to b.cmd completes without problems, errorlevel in b is 0, but after the call errorlevel in a is still 1, which I would definitely not expect after reading the answers to the linked question.
    4. after the jump to :error and call of popd, errorlevel is suddenly reset to 0 - which I would not expect either.

    Does anybody have a clue what might be happening here? I did not accidentally set errorlevel manually, so it should be the system variable, not a userdefined one.

    • marsh-wiggle
      marsh-wiggle over 9 years
      Are you working with setlocal / endlocal anywhere?
    • Arne Mertz
      Arne Mertz over 9 years
      @boboes no setlocal/endlocal in any of the scripts.
  • Arne Mertz
    Arne Mertz over 9 years
    Thanks. You're right I didnt show you the whole ~120 Lines. I'll check for parenthesized code blocks as soon as I'm back at work.
  • Arne Mertz
    Arne Mertz over 9 years
    It was indeed an if block, I edited into the question (the if-block starting after the :: (!) comment. Thansk for clarifying my mistake!
  • dbenham
    dbenham over 7 years
    You jump to the wrong conclusion. There are times when the exact value of ERRORLEVEL is needed, in which case %ERRORLEVEL% is the only reasonable option. The correct conclusion is that you should never define your own ERRORLEVEL environment variable, as it overrides the dynamic value. The same is true for other dynamic pseudo variables like %CD%, %TIME%, %DATE%, %RANDOM%, etc. If the variable is defined, then dynamic behavior is restored by undefining the variable with set "errorlevel="