我注意到在大多数脚本中,两者通常位于同一行,如下所示:
SETLOCAL ENABLEDELAYEDEXPANSION
这两个实际上是独立的命令并且可以写在不同的行上吗?
如果将
ENABLEDELAYEDEXPANSION
设置在脚本的第一行并且直到脚本末尾才禁用,是否会对脚本产生不利影响?
我想你应该明白什么是延迟扩张。现有的答案没有(充分)解释它。
输入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% 仅扩展一次 语句被读取,此时 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!
)
这会打印
x2
和
y2
:每个 1 都会被 2 替换。如果没有
setlocal enabledelayedexpansion
,感叹号就是这样,所以它会回显两次
!b:1=2!
。因为当(块)语句是
read 时,普通环境变量会展开,因此展开 %b:1=2%
使用循环之前
b
的值:
z2
(但未设置时为
y2
)。
如果您在不需要此扩展的脚本中启用此扩展,则仅当脚本包含用感叹号 !LIKE! 括起来的名称时,该脚本的行为才会有所不同。 !这些!。通常名称只是被删除,但如果偶然存在同名变量,那么结果是不可预测的,并且取决于该变量的值和它出现的位置。
SETLOCAL 部分在少数专门(递归)程序中是必需的,但当您希望确保不会偶然修改任何具有相同名称的现有变量,或者如果您想自动删除在中使用的所有变量时,通常使用 SETLOCAL 部分。你的程序。但是,由于没有单独的命令来启用延迟扩展,因此需要此功能的程序还必须包含 SETLOCAL 部分。
@jeb 要使用 SETLOCAL ENABLEDELAYEDEXPANSION 显示感叹号,您需要对它们进行双重转义:
FOR %%a in (TEST.CMD) do if exist %%a echo File exist^^! & echo "Caret^" is not gone and back again^^!