SETLOCAL ENABLEDELAYEDEXPANSION
这两个命令实际上是分开的,可以分别写在不同的行吗?
如果在脚本的第一行设置了ENABLEDELAYEDEXPANSION
并且直到脚本结束都没有禁用它,这会对脚本产生不良影响吗?
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体的复合语句。因此,复合语句内部的IF实际上是将“before”与“after”进行比较,这始终不会相等。同样,下面的示例也无法按预期工作:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%
由于它不会在当前目录中建立文件列表,而是只将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! )
这将打印
x2
和y2
:每个1都被替换为2。如果没有
setlocal enabledelayedexpansion
,感叹号就只是它本身,因此它将两次回显!b:1=2!
。由于普通环境变量在读取(块)语句时会被展开,所以展开
%b:1=2%
使用循环之前b
的值:z2
(但未设置时为y2
)。
%errorlevel%
时遇到了这个问题。在for循环之前添加了setlocal enabledelayedexpansion
,并将检查从%errorlevel%
更改为!errorlevel!
,它就像魔法般地工作了。再次感谢您详细的解释! - LeoVanniniENABLEDELAYEDEXPANSION
是传递给SETLOCAL
命令的一个参数(查看setlocal /?
)。
它的作用在脚本的整个执行期间都有效,或者在执行ENDLOCAL
命令时失效:
当批处理脚本到达结尾时,会为该批处理脚本发出的任何未完成的
SETLOCAL
命令执行隐含的ENDLOCAL
。
特别地,这意味着如果你在脚本中使用SETLOCAL ENABLEDELAYEDEXPANSION
,除非你采取特殊措施,否则任何环境变量的更改都会在其结束时丢失。
ENDLOCAL
被省略是因为当我们到达结尾时,SETLOCAL
停止运行。我们程序员喜欢保持简短...但是不太冗长。 - WesternGun在某些使用延迟扩展的程序中,ENABLEDELAYEDEXPANSION部分是必需的。这些程序会通过用感叹号将变量名括起来来获取在IF或FOR命令内修改过的变量值。
如果你在不需要延迟扩展的脚本中启用了此扩展,只有当脚本包含用感叹号括起来的名称,如!LIKE! !THESE!时,脚本行为会发生变化。通常名称会被删除,但如果恰好存在同名变量,则结果是不可预测的,取决于该变量的值和出现位置。
SETLOCAL部分在很少数专业(递归)程序中是必须的,但通常在想要确保不会偶然修改任何已存在变量的名称或者想要自动删除程序中使用的所有变量时使用。然而,因为没有单独的命令来启用延迟扩展,所以需要此功能的程序也必须包含SETLOCAL部分。
echo "Caret^" is gone!
,您也会遇到问题。 - jebsetlocal
和 enabledelayedexpansion
之间的紧密耦合。如果你想要一个影响环境的脚本,但又需要 enabledelayedexpansion
,那么你需要采取一些 hack 的方法(比如临时脚本文件)来让它工作。 - Steve Hollasch