Exit /b 0 does not set %errorlevel% to 0
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
Related videos on Youtube
![Arne Mertz](https://i.stack.imgur.com/QoiU2.jpg?s=256&g=1)
Arne Mertz
Updated on September 18, 2022Comments
-
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 scriptb.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:
-
md
returns and errorlevel is set to 1, because the directory already exists. - the call to
:seterr
does not have the expected effect, errorlevel remains 1 - the call to
b.cmd
completes without problems, errorlevel inb
is 0, but after the call errorlevel ina
is still 1, which I would definitely not expect after reading the answers to the linked question. - after the jump to
:error
and call ofpopd
, 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 over 9 yearsAre you working with setlocal / endlocal anywhere?
-
Arne Mertz over 9 years@boboes no setlocal/endlocal in any of the scripts.
-
-
Arne Mertz over 9 yearsThanks. 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 over 9 yearsIt was indeed an if block, I edited into the question (the if-block starting after the
:: (!)
comment. Thansk for clarifying my mistake! -
dbenham over 7 yearsYou 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 withset "errorlevel="