批处理文件嵌套 setlocal - 仅设置一次可选参数



我有一个包含一些函数的批处理文件。每个函数都使用 setlocal,以便其变量不会污染主批处理脚本。我注意到我只需要第一次在主批处理脚本中ENABLEDELAYEDEXPANSION参数,而不是在每个嵌套的 setlocal 中。例如:

@echo off
setlocal ENABLEDELAYEDEXPANSION
set VAR=hi
CALL :function
echo bye
exit /b 0
:function
setlocal
echo !VAR!
exit /b 0

批处理文件中是否允许这样做,因为除了下面说明之外,我找不到它的文档。这肯定比为每个函数编写 setlocal 而不是指定其他参数要容易得多。

setlocal /? 关于 ENABLEDELAYEDEXPANSION 是这样说的:

这些修改将持续到匹配的 ENDLOCAL 命令, 无论它们在 SETLOCAL 命令之前的设置如何。

所以也许这意味着即使使用另一个设置,设置也保持不变?

好吧,您可以通过编写一些简单的测试来回答自己的问题。但我会告诉你,答案是肯定的,你只需要启用一次延迟扩展。之后的每个 SETLOCAL 都将继承之前的延迟扩展状态,除非被 DisableDelayedExpansion 显式覆盖。

@echo off
echo delayed Expansion normally starts out disabled: !temp!
setlocal enableDelayedExpansion
echo delayed exapnsion now enabled: !temp!
call :test
exit /b
:test
setlocal
echo delayed expansion still enabled: !temp!
exit /b

如果你正在学习批处理,那么你应该期望做很多实验,因为文档很差,有时甚至是错误的。


仅启用一次延迟扩展

的策略仅在您知道可以在整个脚本中启用延迟扩展时才有效。

诚然,延迟扩展可以批量解决很多令人讨厌的问题,但不幸的是它也会引起问题。

如果值包含!并启用了延迟扩展,则 CALL 参数%1或 FOR 变量%%A的扩展已损坏。我编写的许多中等复杂的脚本都需要仔细管理延迟扩展状态。

在单个例程中,您可以知道任何给定时间的状态。但是在子例程或函数开始时,您可能不知道调用方的状态。作为一般规则,如果我的例程需要特定状态,我会在每个例程的顶部显式启用或禁用延迟扩展。


请注意 - cmd.exe 的每个新实例化都不会继承上一个会话的延迟扩展状态。通常,每个 cmd.exe 会话都会以禁用延迟扩展开始。

这很重要,因为管道和FOR /F %%A IN ('someCommand') DO ...都隐式启动新的 cmd.exe 会话。请参阅为什么延迟扩展在管道代码块内失败?了解更多信息。

最新更新