SETLOCAL和ENABLEDELAYEDEXPANSION如何工作?
我注意到在大多数脚本中,这两者通常在同一行:
SETLOCAL ENABLEDELAYEDEXPANSION
这两者实际上是分开的命令,可以分别写在不同的行上?
设置ENABLEDELAYEDEXPANSION
是否对脚本有不利影响,如果脚本设置在脚本的第一行,并且不会在脚本结束之前禁用脚本?
ENABLEDELAYEDEXPANSION
是传递给SETLOCAL
命令的参数(查看setlocal /?
)
它的效果在脚本或ENDLOCAL
:
当到达批处理脚本结束时,对于由该批处理脚本发出的任何未完成的
SETLOCAL
命令,将执行隐含的ENDLOCAL
。
尤其是,这意味着如果在脚本中使用SETLOCAL ENABLEDELAYEDEXPANSION
,则除非采取特殊措施 ,否则任何环境variables更改都会在其末尾丢失 。
我想你应该明白什么是延迟扩张。 现有的答案没有解释(充分)恕我直言。
键入SET /?
很好地解释了这件事:
延迟的环境variables扩展对于解决在读取一行文本时发生的当前扩展的限制是有用的,而不是在执行时发生。 以下示例演示即时variables扩展的问题:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo If you see this, it worked )
将永远不会显示消息,因为在读取第一个IF语句时,将replaceBOTH IF语句中的%VAR%,因为它在逻辑上包含IF的主体,这是一个复合语句。 所以复合语句中的IF实际上是比较“之前”和“之后”,永远不会相等。 同样,下面的示例将无法按预期工作:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%
因为它不会build立当前目录中的文件列表,而只是将LISTvariables设置为find的最后一个文件。 再一次,这是因为在FOR语句被读取时,%LIST%被扩展一次,并且在那个时候LISTvariables是空的。 所以我们正在执行的实际FOR循环是:
for %i in (*) do set LIST= %i
它只是将LIST设置为find的最后一个文件。
延迟的环境variables扩展允许您在执行时使用不同的字符(感叹号)来扩展环境variables。 如果启用了延迟variables扩展,上面的例子可以写成如下的方式工作:
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%
另一个例子是这个batch file:
@echo off setlocal enabledelayedexpansion set b=z1 for %%a in (x1 y1) do ( set b=%%a echo !b:1=2! )
这打印x2
和y2
:每1被replace为2。
没有setlocal enabledelayedexpansion
,感叹号就是这样,所以它会回声!b:1=2!
两次。
由于正常的环境variables在读取 (块)语句时被扩展,所以展开%b:1=2%
将使用在循环z2
之前的值b
(但未设置时为y2
)。
ENABLEDELAYEDEXPANSION部分在某些使用延迟扩展的程序中是必需的,也就是说,它采用在IF或FOR命令中修改的variables的值,将它们的名字用惊叹号括起来。
如果您在不需要它的脚本中启用此扩展,那么脚本的行为只有包含名称中的惊叹号! !这些!。 通常这个名字只是被擦除,但是如果一个名字相同的variables偶然存在,那么结果是不可预知的,并且取决于这个variables的值和它出现的地方。
SETLOCAL部分在一些专门的(recursion)程序中是必须的,但是当你想要确保不偶然地修改任何具有相同名称的现有variables或者如果你想自动删除你所使用的所有variables程序。 但是,因为没有单独的命令来启用延迟扩展,所以需要此function的程序还必须包含SETLOCAL部分。
一个真正的问题往往存在,因为任何variables设置里面将不会被导出时,该batch file完成。 所以它不可能出口,这就造成了我们的问题。 因此,我只是设置registry总是使用延迟扩展(我不知道为什么它不是默认的,可能是速度或遗留兼容性问题。)