设置EnableDelayedExpansion时未正确评估变量

时间:2016-05-11 11:43:04

标签: batch-file cmd

我有一个显然未在条件中正确评估的变量。

方案如下:我创建了一个使用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
  6. 可能的解决方法:

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

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

    3. 我想继续使用SetLocal而不是ParamsNotEqual的值,而且,我希望将子例程中的变量保持为ErrorLevel

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

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

1 个答案:

答案 0 :(得分:4)

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

这一行包含问题。

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

您应该始终使用SET的扩展语法和周围的引号

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