定点扩张和启动延伸是如何工作的?

我注意到在大多数脚本中,这两个通常在同一行中:

SETLOCAL ENABLEDELAYEDEXPANSION

这两个命令实际上是不同的命令并且可以写在不同的行上吗?

如果在脚本的第一行设置了 ENABLEDELAYEDEXPANSION并且直到脚本结束才禁用它,那么设置 ENABLEDELAYEDEXPANSION会对脚本产生不利影响吗?

132862 次浏览

ENABLEDELAYEDEXPANSION是传递给 SETLOCAL命令的参数(参见 setlocal /?)

它的效果在剧本的持续时间内存在,或者说是 ENDLOCAL:

当到达批处理脚本的结尾时,隐含的 ENDLOCAL为 执行该批发出的任何未执行的 SETLOCAL命令 剧本。

特别是,这意味着如果在脚本中使用 SETLOCAL ENABLEDELAYEDEXPANSION,除非使用 采取特别措施,否则使用 任何环境变量的改变最终都会消失

在某些使用延迟展开的程序中,ENABLEDELAYEDEXPANION 部分是必需的,也就是说,它通过将变量的名称用感叹号括起来,获取 IF 或 FOR 命令中修改过的变量的值。

If you enable this expansion in a script that does not require it, the script behaves different only if it contains names enclosed in exclamation-marks !LIKE! !THESE!. Usually the name is just erased, but if a variable with the same name exist by chance, then the result is unpredictable and depends on the value of such variable and the place where it appears.

SETLOCAL 部分在一些专门的(递归的)程序中是必需的,但是当你想确保不会偶然地修改任何存在的同名变量,或者你想自动删除程序中使用的所有变量时,通常会使用 SETLOCAL 部分。但是,由于没有单独的命令来启用延迟展开,所以要求这样做的程序还必须包括 SETLOCAL 部分。

我认为你应该理解是什么延迟了 的扩展。恕我直言,现有的答案并不能充分地解释它。

键入 SET /?可以很好地解释这个问题:

延迟的环境变量扩张对于出行很有帮助 当一条直线的时候发生的当前扩展的局限性 文本是读取的,而不是执行时读取的 证明了立即变量展开的问题:

set VAR=before
if "%VAR%" == "before" (
set VAR=after
if "%VAR%" == "after" @echo If you see this, it worked
)

将永远不会显示消息,因为两个 IF 语句中的% VAR% 在读取第一个 IF 语句时被替换,因为它在逻辑上 包含 IF 的主体,它是一个复合语句 在复合语句中,实际上是将“ before”与 “之后”永远不会相等。同样,下面的例子 不会像预期的那样奏效:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %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%

另一个例子是这个批处理文件:

@echo off
setlocal enabledelayedexpansion
set b=z1
for %%a in (x1 y1) do (
set b=%%a
echo !b:1=2!
)

这个输出 x2y2: 每个1被一个2替换。

如果没有 setlocal enabledelayedexpansion,感叹号就是这样,所以它会回应 !b:1=2!两次。

因为当(块)语句为 时,正常的环境变量被展开,所以展开 %b:1=2%时使用的值是 b在循环之前的值: z2(未设置时为 y2)。

真正的问题经常存在,因为当批处理文件完成时,内部设置的任何变量都不会被导出。所以它不可能出口,这给我们带来了问题。因此,我只是将注册表设置为 ALWAYS 使用的延迟扩展(我不知道为什么它不是默认的,可能是速度或遗留兼容性问题)