【发布时间】:2016-05-11 11:43:03
【问题描述】:
我有一个变量,显然没有在条件下正确评估。
场景如下:我创建了一个设置为SetLocal EnableExtensions 的批处理文件,然后它有一个设置为SetLocal EnableExtensions EnableDelayedExpansion 的主例程。主例程从传递两个参数的嵌套if 语句中调用一个子例程,并得到一个变量作为结果。被调用的子程序设置为SetLocal EnableExtensions。
问题是在评估返回子程序的变量时,显然该变量没有被正确评估:前一行被回显并确认为零的变量使if !variable! EQU 0语句莫名其妙地返回FALSE.
更多解释和细节在下面的代码之后。
示例代码(概念证明)
@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
如果您运行此脚本,您将看到子例程正确地将ParamsNotEqual 变量返回为0,然后echo 行正确显示正常解析变量和延迟变量的值:
InLoop: ErrorLevel: 0, ErrorStatus: 0, ParamsNotEqual: 2
InLoopDelayed: ErrorLevel: 0, ErrorStatus: 0, ParamsNotEqual: 0
但是当评估条件if !ParamsNotEqual! EQU 0 时,它就失败了。设置@echo on 并没有说明任何事情,因为延迟的变量会在执行时间上扩展,所以我看不到那里真正正在评估什么。
到目前为止我所做的测试
没有效果的事情,所以一直失败:
- 为整个脚本设置
SetLocal EnableExtensions EnableDelayedExpansion - 也为子程序设置
SetLocal EnableExtensions EnableDelayedExpansion。 - 之前未设置
ParamsNotEqual变量。 - 用引号或方括号评估围绕它的条件,或者使用
==代替EQU。 - 评估
if !ParamsNotEqual! EQU 2(这是变量的初始值)也会返回FALSE
可能的解决方法:
使用
!ErrorLevel!代替!ParamsNotEqual!可以正常工作。这看起来很合乎逻辑,因为 ErrorLevel 是一个系统变量,而不是用户定义的变量。没有为子例程设置
SetLocal,因此子例程变量不与脚本的其余部分隔离,使主例程自动正常工作。这对我来说毫无意义,但让我认为这个错误可能是由于在设置EnableDelayedExpansion时从嵌套if中调用子例程时或使用嵌套SetLocal语句时的某种限制。
我想继续使用ParamsNotEqual 的值而不是ErrorLevel,并且我想保持子例程中的变量与SetLocal 隔离。
所以,我的问题是:这种奇怪的行为是因为我做错了什么,还是在设置EnableDelayedExpansion 时命令处理器处理变量的方式受到限制?
任何提示将不胜感激。如果您需要对上述内容进行任何进一步的测试或澄清,请不要犹豫。非常感谢。
【问题讨论】:
标签: batch-file cmd