.bat文件中的奇怪范围问题

时间:2008-11-20 15:16:42

标签: scope batch-file

我正在写一个简单的.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,但这似乎并不那么干净。

导致这种行为的原因是什么?代码块中的变量是否存在某种限制?

3 个答案:

答案 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可以根据你的需要填充变量。