【问题标题】:Variable not being correctly evaluated when EnableDelayedExpansion is set设置 EnableDelayedExpansion 时未正确评估变量
【发布时间】: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 并没有说明任何事情,因为延迟的变量会在执行时间上扩展,所以我看不到那里真正正在评估什么。

到目前为止我所做的测试

没有效果的事情,所以一直失败:

  1. 为整个脚本设置SetLocal EnableExtensions EnableDelayedExpansion
  2. 也为子程序设置SetLocal EnableExtensions EnableDelayedExpansion
  3. 之前未设置ParamsNotEqual变量。
  4. 用引号或方括号评估围绕它的条件,或者使用== 代替EQU
  5. 评估if !ParamsNotEqual! EQU 2(这是变量的初始值)也会返回FALSE

可能的解决方法:

  1. 使用!ErrorLevel! 代替!ParamsNotEqual! 可以正常工作。这看起来很合乎逻辑,因为 ErrorLevel 是一个系统变量,而不是用户定义的变量。

  2. 没有为子例程设置SetLocal,因此子例程变量不与脚本的其余部分隔离,使主例程自动正常工作。这对我来说毫无意义,但让我认为这个错误可能是由于在设置EnableDelayedExpansion 时从嵌套if 中调用子例程时或使用嵌套SetLocal 语句时的某种限制。

我想继续使用ParamsNotEqual 的值而不是ErrorLevel,并且我想保持子例程中的变量与SetLocal 隔离。

所以,我的问题是:这种奇怪的行为是因为我做错了什么,还是在设置EnableDelayedExpansion 时命令处理器处理变量的方式受到限制?

任何提示将不胜感激。如果您需要对上述内容进行任何进一步的测试或澄清,请不要犹豫。非常感谢。

【问题讨论】:

    标签: batch-file cmd


    【解决方案1】:

    结果是正确的,因为 ParamsNotEqual 不等于 0,因为您将其设置为 0<space>

    这一行包含问题。

    endlocal & set ParamsNotEqual=%ParamsNotEqual% & exit /b %ErrorStatus%
    

    您应该始终使用带有引号的SET 的扩展语法

    endlocal & set "ParamsNotEqual=%ParamsNotEqual%" & ...
    

    【讨论】:

    • 伙计,我现在正用头撞桌子:那个空间正是问题所在。非常感谢! :-)
    猜你喜欢
    • 2016-11-16
    • 2023-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 1970-01-01
    相关资源
    最近更新 更多