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

loo*_*oop 2 windows batch-file

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

@echo off
setlocal ENABLEDELAYEDEXPANSION

set VAR=hi
CALL :function

echo bye
exit /b 0

:function
setlocal
echo !VAR!
exit /b 0
Run Code Online (Sandbox Code Playgroud)

这是否允许在批处理文件中,因为除非如下所述,否则我无法找到它.这setlocal对于为每个函数编写而不是指定其他参数来说肯定要容易得多.

setlocal /? 关于ENABLEDELAYEDEXPANSION说这个:

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

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

dbe*_*ham 6

那么,您可以通过编写一些简单的测试来回答您自己的问题.但我会告诉你答案是肯定的,你只需要启用延迟扩展一次.之后的每个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
Run Code Online (Sandbox Code Playgroud)

如果你正在学习批处理,那么你应该期待进行大量的实验,因为文档很差,有时甚至是错误的.


只有当您知道在整个脚本中启用延迟扩展时,才能实现仅启用延迟扩展的策略.

确实,延迟扩展在批处理中解决了许多令人讨厌的问题,但遗憾的是它也可能导致问题.

如果值包含并且启用了延迟扩展,则CALL参数%1或FOR变量的扩展将%%A被破坏!.我编写的这么多中等复杂的脚本需要仔细管理延迟扩展状态.

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


需要注意的是 - cmd.exe的每个新实例都不会继承先前会话的延迟扩展状态.通常,每个cmd.exe会话都会启动,并禁用延迟扩展.

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