4

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.

  • Are you working with setlocal / endlocal anywhere? – marsh-wiggle Dec 30 '14 at 10:14
  • @boboes no setlocal/endlocal in any of the scripts. – Arne Mertz Dec 30 '14 at 10:20
7

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
  • 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 Dec 31 '14 at 15:33
  • It was indeed an if block, I edited into the question (the if-block starting after the :: (!) comment. Thansk for clarifying my mistake! – Arne Mertz Jan 2 '15 at 11:16
0

Although this request is resolved, there is another reason for a behaviour like described. Example, put this into a batch file and run it:

@set errorlevel=
@dir >nul
@if %errorlevel% equ 0 (echo 1: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo A: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 2: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo B: Correctly detected: An error!) else echo.

@set errorlevel=7
@dir >nul
@if %errorlevel% equ 0 (echo 3: Correctly detected: No error!) else echo.
@if not errorlevel 1 (echo C: Correctly detected: No error!) else echo.
@dir nonexistent >nul
@if %errorlevel% neq 0 (echo 4: Correctly detected: An error!) else echo.
@if errorlevel 1 (echo D: Correctly detected: An error!) else echo.

If you observe the output of this batch, the line starting with 3: will be missing, and the line starting with 4: will be mischievous.

Conclusion: Do not evaulate the errorlevel with %errorlevel% but with if errorlevel.

  • 1
    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=" – dbenham Dec 29 '16 at 12:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.