SETLOCAL和ENABLEDELAYEDEXPANSION如何工作?

Mec*_*ash 47 cmd batch-file

我注意到在大多数脚本中,两者通常在同一行中:

SETLOCAL ENABLEDELAYEDEXPANSION
Run Code Online (Sandbox Code Playgroud)

这两个实际上是单独的命令,可以写在不同的行上吗?

ENABLEDELAYEDEXPANSION如果脚本设置在脚本的第一行并且在脚本结束之前未禁用,那么设置是否会对脚本产生负面影响?

Mic*_*ter 99

我想你应该明白推迟扩张什么.现有答案没有解释(充分)恕我直言.

打字很SET /?合理地解释了这个问题:

延迟环境变量扩展对于解决当读取文本行时发生的当前扩展的限制很有用,而不是在执行时.以下示例演示了立即变量扩展的问题:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)
Run Code Online (Sandbox Code Playgroud)

永远不会显示消息,因为在读取第一个IF语句时,BOTH IF语句中的%VAR%被替换,因为它在逻辑上包含IF的主体,这是一个复合语句.因此,复合语句中的IF实际上是在比较"之前"和"之后",它永远不会相等.同样,以下示例将无法按预期工作:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
Run Code Online (Sandbox Code Playgroud)

因为它不会在当前目录中建立文件列表,而只是将LIST变量设置为找到的最后一个文件.同样,这是因为%LIST%在读取FOR语句时只展开一次,并且此时LIST变量为空.所以我们正在执行的实际FOR循环是:

for %i in (*) do set LIST= %i
Run Code Online (Sandbox Code Playgroud)

只是将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%
Run Code Online (Sandbox Code Playgroud)

另一个例子是这个批处理文件:

@echo off
setlocal enabledelayedexpansion
set b=z1
for %%a in (x1 y1) do (
 set b=%%a
 echo !b:1=2!
)
Run Code Online (Sandbox Code Playgroud)

这打印x2并且y2:每1个被2替换.

没有setlocal enabledelayedexpansion,感叹号只是那样,所以它会回响!b:1=2!两次.

因为在读取(块)语句时会扩展常规环境变量,所以扩展%b:1=2%使用b循环之前的值:( z2但是y2未设置时).

  • 需要明确的是,如果您的命令中没有感叹号,则延迟扩展不会起任何作用,对吧? (2认同)
  • 对!感叹号确实有其他微妙的[效果](https://ss64.com/nt/delayedexpansion.html). (2认同)

Ale*_* K. 22

ENABLEDELAYEDEXPANSION是传递给SETLOCAL命令的参数(看看setlocal /?)

它的效果在脚本的持续时间内存在,或者ENDLOCAL:

当到达批处理脚本的末尾时,对该批处理脚本发出的ENDLOCAL任何未完成的SETLOCAL命令执行隐含.

特别是,这意味着如果您SETLOCAL ENABLEDELAYEDEXPANSION在脚本中使用,除非您采取特殊措施,否则任何环境变量更改都会丢失.

  • 那问题的第二部分呢? (7认同)

Aac*_*ini 9

在某些使用延迟扩展的程序中,ENABLEDELAYEDEXPANSION部分是必需的,即通过将其名称括在感叹号中来获取在IF或FOR命令中修改的变量的值.

如果在不需要它的脚本中启用此扩展,则只有当脚本包含用感叹号括起来的名称时,脚本的行为才会有所不同!LIKE!!这些!.通常名称只是被删除,但如果偶然存在具有相同名称的变量,则结果是不可预测的,并且取决于此变量的值及其出现的位置.

SETLOCAL部分只需要几个专门的(递归)程序,但是当你想要确保不要偶然修改任何现有的同名变量或者你想要自动删除你使用的所有变量时,通常会使用它.程序.但是,由于没有单独的命令来启用延迟扩展,因此需要此功能的程序还必须包含SETLOCAL部分.