代码之家  ›  专栏  ›  技术社区  ›  Herms

.bat文件中存在奇怪的作用域问题

  •  17
  • Herms  · 技术社区  · 15 年前

    我正在写一个简单的.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
    

    为什么代码块内的echo没有获取变量的新值?在我正在编写的实际代码中,我需要构建一些变量,并在if/else的范围内引用它们。我可以将此切换为使用标签和goto,而不是if/else,但这似乎没有那么干净。

    是什么导致了这种行为?代码块中的变量是否有某种限制?

    3 回复  |  直到 15 年前
        1
  •  26
  •   user33675    15 年前

    您遇到了cmd的静态变量扩展问题。模式变量仅计算一次。如果省略@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语句中的%VAR%都是 当第一个 包括IF的主体,它是 复合语句的内部是 这永远不会是平等的。同样地, 下面的示例将不起作用

    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%
    

    当前目录中的文件,但 变量设置为找到的最后一个文件。 同样,这是因为%LIST%是 当为时仅扩展一次 列表变量为空。所以 我们正在执行的实际FOR循环是:

    for %i in (*) do set LIST= %i
    

    找到最后一个文件。

    延迟环境变量展开 在以下位置展开环境变量: 执行时间。If延迟变量 如果启用了扩展,请执行上述操作 按计划工作:

    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%
    
        2
  •  2
  •   alex alex    15 年前

    setlocal EnableDelayedExpansion

    将启用/v标志

        3
  •  -2
  •   Harry Lime    15 年前

    看起来读写操作使用不同的作用域规则。

    set MODE=FOOBAR
    

    它将按预期工作。因此,您可能需要使用一个复杂的序列if/elses来按照您的意愿填充变量。