10

Can anyone please help me understand the behaviour of %ERRORLEVEL% variable and why it's not being set after a CALL while being inside an IF, i.e. the ECHO %ERRORLEVEL%.2 line?

@ECHO OFF
SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

IF %ERRORLEVEL% == 0 (
  ECHO %ERRORLEVEL%.1
  CALL :FOO
  ECHO %ERRORLEVEL%.2
  IF ERRORLEVEL 42 ECHO 42.3
)

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

STDOUT

C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
0.2
42.3

However, without IF the %ERRORLEVEL% variable is set as expected.

@ECHO OFF
SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

REM IF %ERRORLEVEL% == 0 (
  ECHO %ERRORLEVEL%.1
  CALL :FOO
  ECHO %ERRORLEVEL%.2
  IF ERRORLEVEL 42 ECHO 42.3
REM )

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

STDOUT

C:\Users\Ilya.Kozhevnikov\Dropbox>foo.bat
Environment variable ERRORLEVEL not defined
0.0
0.1
42.2
42.3
Ilya Kozhevnikov
  • 10,242
  • 4
  • 40
  • 70
  • possible duplicate of [windows batch SET inside IF not working](http://stackoverflow.com/questions/9102422/windows-batch-set-inside-if-not-working) – Laf Jul 21 '14 at 13:46
  • See the question I've marked as being a duplicate of. This explains exactly what is happening with your script, and what you have to do to fix the problem. – Laf Jul 21 '14 at 13:47

2 Answers2

13

When the cmd parser reads a line or a block of lines (the code inside the parenthesis), all variable reads are replaced with the value inside the variable before starting to execute the code. If the execution of the code in the block changes the value of the variable, this value can not be seen from inside the same block, as the read operation on the variable does not exist, it was replaced with the value in the variable

To solve it, you need to enable delayed expansion, and, where needed, change the syntax from %var% to !var!, indicating to the parser that the read operation needs to be delayed until the execution of the command.

@ECHO OFF

setlocal enabledelayedexpansion

SET ERRORLEVEL
VERIFY > NUL

ECHO %ERRORLEVEL%.0
IF ERRORLEVEL 1 ECHO SNAFU

IF %ERRORLEVEL% == 0 (
  ECHO !ERRORLEVEL!.1
  CALL :FOO
  ECHO !ERRORLEVEL!.2
  IF ERRORLEVEL 42 ECHO 42.3
)

GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF
MC ND
  • 69,615
  • 8
  • 84
  • 126
2

MC ND answered the question already well.

Here is an alternative code showing both: expanded and delayed expansion of ERRORLEVEL.

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
VERIFY > NUL

ECHO !ERRORLEVEL!.0 delayed
ECHO %ERRORLEVEL%.0 expanded
IF ERRORLEVEL 1 ECHO SNAFU

IF !ERRORLEVEL! == 0 (
  ECHO !ERRORLEVEL!.1 delayed
  ECHO %ERRORLEVEL%.1 expanded
  CALL :FOO
  ECHO !ERRORLEVEL!.2 delayed
  ECHO %ERRORLEVEL%.2 expanded
)
ENDLOCAL
GOTO :EOF

:FOO
  EXIT /B 42
GOTO :EOF

Microsoft describes the behavior of delayed expansion in help of command set which can be read in a command prompt window after entering set /? or help set

Community
  • 1
  • 1
Mofi
  • 46,139
  • 17
  • 80
  • 143