我正在写一个简单的.bat文件,我遇到了一些奇怪的行为.有几个地方我必须做一个简单的if/else,但块内的代码似乎没有正常工作.
这是一个演示错误的简单案例:
@echo off set MODE=FOOBAR if "%~1"=="" ( set MODE=all echo mode: %MODE% ) else ( set MODE=%~1 echo mode: %MODE% ) echo mode: %MODE%
我得到的输出是:
C:\>test.bat test mode: FOOBAR mode: test
为什么代码块中的回声没有得到变量的新值?在我写的实际代码中,我需要构建一些变量并在if/else的范围内引用它们.我可以将其切换为使用标签和gotos而不是if/else,但这似乎并不那么干净.
是什么导致这种行为?代码块中的变量是否存在某种限制?
您遇到了cmd静态变量扩展的问题.MODE变量仅评估一次.如果省略@echo离线,你可以看到这个.
从集/?文档:
最后,增加了对延迟环境变量扩展的支持.默认情况下,此支持始终处于禁用状态,但可以通过/ V命令行开关启用/禁用CMD.EXE.见CMD /?
延迟环境变量扩展对于解决当读取文本行时发生的当前扩展的限制很有用,而不是在执行时.以下示例演示了立即变量扩展的问题:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo If you see this, it worked )永远不会显示消息,因为在读取第一个IF语句时,BOTH IF语句中的%VAR%被替换,因为它在逻辑上包含IF的主体,这是一个复合语句.因此,复合语句中的IF实际上是在比较"之前"和"之后",它永远不会相等.同样,以下示例将无法按预期工作:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%因为它不会在当前目录中建立文件列表,而只是将LIST变量设置为找到的最后一个文件.同样,这是因为%LIST%在读取FOR语句时只展开一次,并且此时LIST变量为空.所以我们正在执行的实际FOR循环是:
for %i in (*) do set LIST= %i只是将LIST设置为找到的最后一个文件.
延迟环境变量扩充允许您使用一个不同的字符(惊叹号)在执行时间扩充环境变量.如果启用了延迟变量扩展,则可以按如下方式编写上述示例以按预期工作:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo If you see this, it worked ) set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST%