Reputation: 423
I have a variable that apparently is not being correctly evaluated in a condition.
The scenario is the following: I've made a batch file that is set with SetLocal EnableExtensions
, then it has a main routine that is set with SetLocal EnableExtensions EnableDelayedExpansion
. The main routine calls a subroutine from within a nested if
statement passing two parameters, and it gets a variable as a result. The subroutine being called is set with SetLocal EnableExtensions
.
Problem is that when evaluating the variable that returns the subroutine, apparently the variable is not being correctly evaluated: a variable that one line before is echoed and confirmed to be equal to zero makes an if !variable! EQU 0
statement inexplicably return FALSE
.
More explanations and details after the code below.
@echo off
SetLocal EnableExtensions
rem Initialize variables
rem -------------------------------------------------------------------------------
set ErrorStatus=0
set PreConditionOne=1
set PreConditionTwo=1
set ValueOne=50
set ValueTwo=50
rem - Main Routine
rem -------------------------------------------------------------------------------
SetLocal EnableExtensions EnableDelayedExpansion
rem Setting initial values for flag variables, value can be: 0=NO, 1=YES, 2=Not Checked.
set PreCheckFail=2
set ParamsNotEqual=2
rem Prechecks: Preconditions must be met in order to check variables.
echo Checking PreConditions.
if %PreConditionOne%==1 (
echo OK: First PreCondition is met.
echo Checking Second PreCondition.
if %PreConditionTwo%==1 (
echo OK: Second PreCondition is met.
echo Calling subroutine to check if values match.
call :Subroutine %ValueOne% %ValueTwo%
echo Back from subroutine.
echo InLoop: ErrorLevel: %ErrorLevel%, ErrorStatus: %ErrorStatus%, ParamsNotEqual: %ParamsNotEqual%
echo InLoopDelayed: ErrorLevel: !ErrorLevel!, ErrorStatus: !ErrorStatus!, ParamsNotEqual: !ParamsNotEqual!
rem This condition fails to correctly check ParamsNotEqual, it works fine with ErrorLevel.
if !ParamsNotEqual! EQU 0 (
echo OK Parameteres verified successfully.
set PreCheckFail=0
) else (
echo ERROR Parameter verification failed.
set PreCheckFail=1
)
) else (
echo ERROR: Second PreCondition is not met.
set PreCheckFail=1
)
) else (
echo ERROR: First PreCondition is not met.
set PreCheckFail=1
)
echo OutLoop: ErrorLevel: %ErrorLevel%, ErrorStatus: %ErrorStatus%, ParamsNotEqual: %ParamsNotEqual%
echo PreCheckFail: %PreCheckFail%
if %PreCheckFail% EQU 0 (echo "PreCheckFail IS ZERO") else (echo "PreCheckFail NOT ZERO")
endlocal
goto :Finish
:Subroutine
rem Subroutine
rem -------------------------------------------------------------------------------
SetLocal EnableExtensions
set ParamOne=%1
set ParamTwo=%2
echo This is the subroutine.
echo The first parameter passed is: %ParamOne%
echo The second parameter passed is: %ParamTwo%
if "%ParamOne%"=="%ParamTwo%" (
echo OK^! Both variables are equal.
set ParamsNotEqual=0
set ErrorStatus=0
) else (
echo ERROR^! Both variables are different.
set ParamsNotEqual=1
set ErrorStatus=1
)
echo EndSub: ErrorLevel: %ErrorLevel%, ErrorStatus: %ErrorStatus%, ParamsNotEqual: %ParamsNotEqual%
endlocal & set ParamsNotEqual=%ParamsNotEqual% & exit /b %ErrorStatus%
:Finish
endlocal
If you run this script, you will see that the subroutine correctly returns the ParamsNotEqual
variable as 0
, then the echo
lines correctly show the values for both the normally parsed variables and the delayed ones:
InLoop: ErrorLevel: 0, ErrorStatus: 0, ParamsNotEqual: 2
InLoopDelayed: ErrorLevel: 0, ErrorStatus: 0, ParamsNotEqual: 0
But when the condition if !ParamsNotEqual! EQU 0
is evaluated, it just fails. Setting @echo on
does not clarify anything, as the delayed variables are expanded on execution time so I cannot see what is really being evaluated there.
Things that have no effect so it keeps failing:
SetLocal EnableExtensions EnableDelayedExpansion
for the whole scriptSetLocal EnableExtensions EnableDelayedExpansion
for the subroutine too.ParamsNotEqual
variable.==
instead of EQU
. if !ParamsNotEqual! EQU 2
(which is the initial value of the variable) also returns FALSE
Possible workarounds:
Using !ErrorLevel!
instead of !ParamsNotEqual!
works fine. This looks logic, as ErrorLevel is a system variable, not a user-defined one.
Not setting SetLocal
for the subroutine, hence having the subroutine variables not isolated from the rest of the script, makes the main routine automagically work fine as it is. This has no sense to me but makes me think that this error may be due to some kind of restriction either when calling a subroutine from within a nested if
when EnableDelayedExpansion
is set, or with using nested SetLocal
statements.
I would like to keep using the value of ParamsNotEqual
instead of ErrorLevel
, and also, I would like to keep the variables within the subroutine isolated with SetLocal
.
So, my question: Is this strange behaviour due to something am I doing wrong or is this a restriction in the way the command processor handles variables when EnableDelayedExpansion
is set?
Any hint will be greatly appreciated. If you need any further tests or clarification on the above don't hesitate on asking. A lot of thanks in advance.
Upvotes: 4
Views: 187
Reputation: 82247
The result is correct as ParamsNotEqual
isn't equal to 0
, as you set it to 0<space>
.
This line contains the problem.
endlocal & set ParamsNotEqual=%ParamsNotEqual% & exit /b %ErrorStatus%
You should always use the extended syntax of SET
with surrounding quotes
endlocal & set "ParamsNotEqual=%ParamsNotEqual%" & ...
Upvotes: 4