为什么我不能在if语句中获得延迟扩展变量的子字符串?

unc*_*eat 12 cmd if-statement batch-file delayedvariableexpansion

为什么字符串操作在if语句中内联工作而不使用延迟扩展变量 - 否则失败.例如:

set test=testString
if %test:~0,4%==test echo Success
Run Code Online (Sandbox Code Playgroud)

这工作正常; 回来Success.但是,如果我执行以下操作:

setLocal enableDelayedExpansion
set test=testString
if !test:~0,4!==test echo Success
Run Code Online (Sandbox Code Playgroud)

我收到错误 - 4!==test was unexpected at this time.

显然你可以通过在if语句中set comp=!test:~0,4!使用!comp!变量来做到这一点.

npo*_*aka 9

,;=<tab>并且<space>是cmd.exe的分隔符,并且在许多情况下如果它们不在引号中并且像空格一样被忽略.可能在这种情况下,被视为第一个操作数的结尾并且IF惊讶于没有有效的比较运算符,例如这将打印yep:

if a   ;==;,,=a echo yep
Run Code Online (Sandbox Code Playgroud)

(但如果操作数的第一部分中有相同的符号,则不起作用)

但这不会:

if "a ;" == ";,,=a" echo yep

所以要IF在使用逗号时创建一个有效的表达式,你需要引号.这将有效

setLocal enableDelayedExpansion
set test=testString
if "!test:~0,4!" == "test" echo Success
Run Code Online (Sandbox Code Playgroud)

没有延迟扩展替换立即进行,这将没有引号:

set test=testString
setlocal disableDelayedExpansion
if %test:~0,4% == test echo Succes
endlocal
Run Code Online (Sandbox Code Playgroud)

出于同样的原因,这将被视为错误的语法表达式(请参阅jeb的评论):

set "test="
setlocal disableDelayedExpansion
if %test% == test echo Succes
endlocal
Run Code Online (Sandbox Code Playgroud)

可能不是完整的答案,但应该是关闭的.因为两者echo !test:~0,4!并且echo %test:~0,4%将在没有引号的情况下工作仍然存在为什么完全IF失败的问题- 可能因为IF命令使用自己的解析器

作为结论 - 在比较字符串时使用引号总是好的IF:

  1. 延迟扩展逗号和分号会引起麻烦.
  2. 没有延迟扩展未定义的变量将导致麻烦.

  • 关键是delayedexpansion恰好是 - 延迟到执行时间.在PARSE时,%var ...%被解析并被替换,但是!var ...!不是 - 它将在RUN时被替换并被解释为一个简单的字符串.解析器因此看到*string*[separator]*string*==*string*但是期望*string*[operator]*string*.解析器看到的第二个字符串与其有效运算符列表不匹配,因此解析器调用该命令无效. (5认同)

dbe*_*ham 9

npocmaka正确地诊断出IF命令获得自己的特殊解析阶段的问题,并且变量扩展中的令牌分隔符导致问题.

替换也会导致问题:

:: This fails
if !test:String=!==test echo Success
Run Code Online (Sandbox Code Playgroud)

正常扩展工作的原因是因为它发生在IF解析之前,但是 IF解析之后发生延迟扩展.

使用引号的替代方法是转义问题字符.

:: Both of these work
if !test:~0^,4!==test echo Success
if !test:String^=!==test echo Success
Run Code Online (Sandbox Code Playgroud)