我正在写一个简单的.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,但这似乎并不那么干净。
导致这种行为的原因是什么?代码块中的变量是否存在某种限制?
答案 0 :(得分:26)
您遇到了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 )
永远不会显示消息,因为 BOTH IF语句中的%VAR%是 当第一个IF被替换 声明是从逻辑上读的 包括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%
答案 1 :(得分:2)
setlocal EnableDelayedExpansion
将启用/ v标志
答案 2 :(得分:-2)
看起来读写使用不同的范围规则。
如果你删除了这一行
set MODE=FOOBAR
它将按预期工作。所以你可能需要有一个复杂的系列,如果if / elses可以根据你的需要填充变量。