SETLOCAL 和 ENABLEDELAYEDEXPANSION 如何工作?

发布于 2024-11-19 14:53:19 字数 211 浏览 1 评论 0原文

我注意到在大多数脚本中,两者通常位于同一行,如下所示:

SETLOCAL ENABLEDELAYEDEXPANSION

这两个实际上是单独的命令并且可以写在单独的行上吗?

如果设置 ENABLEDELAYEDEXPANSION 是在脚本的第一行设置并且直到脚本末尾才禁用,是否会对脚本产生不利影响?

I notice in most scripts, the two are usually in the same line as so:

SETLOCAL ENABLEDELAYEDEXPANSION

Are the two in fact separate commands and can be written on separate lines?

Will setting ENABLEDELAYEDEXPANSION have an adverse effect on a script if it is set on the first lines of the script and not disabled until the end of the script?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

薄凉少年不暖心 2024-11-26 14:53:20

我想你应该明白什么是延迟扩展。现有的答案并不能(充分)解释它。恕我直言。

输入 SET /? 很好地解释了这一点:

延迟环境变量扩展对于解决问题很有用
当前扩展的局限性,当一行
文本是在读取时读取的,而不是在执行时读取的。下面的例子
演示了立即变量扩展的问题:

设置 VAR=之前
如果“%VAR%”==“之前”(
    设置VAR=之后
    if "%VAR%" == "after" @echo 如果你看到这个,它就起作用了
)

永远不会显示该消息,因为两个 IF 语句中都有 %VAR%
当读取第一个 IF 语句时被替换,因为它在逻辑上
包括 IF 的主体,它是一个复合语句。所以如果
复合语句内部实际上是在比较“before”与
“之后”永远不会相等。同样,下面的例子
将无法按预期工作:

<前><代码>设置列表=
对于 (*) 中的 %i,请设置 LIST=%LIST% %i
回显%列表%

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

对于 (*) 中的 %i 设置 LIST= %i

它只是不断将 LIST 设置为找到的最后一个文件。

延迟环境变量扩展允许您使用不同的
字符(感叹号)来扩展环境变量
执行时间。如果启用延迟变量扩展,则上述
示例可以编写如下以按预期工作:

设置 VAR=之前
如果“%VAR%”==“之前”(
    设置VAR=之后
    如果“!VAR!” ==“after”@echo 如果你看到这个,它就起作用了
)

设置列表=
对于 (*) 中的 %i,请设置 LIST=!LIST! %我
回显%列表%

另一个示例是此批处理文件:

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

这会打印 x2y2:每个 1 都会被 2 替换。

没有 setlocalenabledelayedexpansion,感叹号就是这样,所以它会回显 !b:1=2! 两次。

由于读取(块)语句时会扩展普通环境变量,因此扩展 %b:1=2% 使用 b 之前的值循环:z2(但未设置时y2)。

I think you should understand what delayed expansion is. The existing answers don't explain it (sufficiently) IMHO.

Typing SET /? explains the thing reasonably well:

Delayed environment variable expansion is useful for getting around
the limitations of the current expansion which happens when a line of
text is read, not when it is executed. The following example
demonstrates the problem with immediate variable expansion:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

would never display the message, since the %VAR% in BOTH IF statements
is substituted when the first IF statement is read, since it logically
includes the body of the IF, which is a compound statement. So the IF
inside the compound statement is really comparing "before" with
"after" which will never be equal. Similarly, the following example
will not work as expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

in that it will NOT build up a list of files in the current directory,
but instead will just set the LIST variable to the last file found.
Again, this is because the %LIST% is expanded just once when the FOR
statement is read, and at that time the LIST variable is empty. So the
actual FOR loop we are executing is:

for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time. If delayed variable expansion is enabled, the above
examples could be written as follows to work as intended:

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%

Another example is this batch file:

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

This prints x2 and y2: every 1 gets replaced by a 2.

Without setlocal enabledelayedexpansion, exclamation marks are just that, so it will echo !b:1=2! twice.

Because normal environment variables are expanded when a (block) statement is read, expanding %b:1=2% uses the value b has before the loop: z2 (but y2 when not set).

听风念你 2024-11-26 14:53:20

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

它的效果在脚本的持续时间内有效,或者 <代码>ENDLOCAL:

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

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

ENABLEDELAYEDEXPANSION is a parameter passed to the SETLOCAL command (look at setlocal /?)

Its effect lives for the duration of the script, or an ENDLOCAL:

When the end of a batch script is reached, an implied ENDLOCAL is
executed for any outstanding SETLOCAL commands issued by that batch
script.

In particular, this means that if you use SETLOCAL ENABLEDELAYEDEXPANSION in a script, any environment variable changes are lost at the end of it unless you take special measures.

[旋木] 2024-11-26 14:53:20

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

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

SETLOCAL 部分在少数专用(递归)程序中是必需的,但当您希望确保不会偶然修改任何具有相同名称的现有变量,或者如果您想自动删除程序中使用的所有变量时,通常会使用 SETLOCAL 部分。程序。但是,由于没有单独的命令来启用延迟扩展,因此需要此功能的程序还必须包含 SETLOCAL 部分。

The ENABLEDELAYEDEXPANSION part is REQUIRED in certain programs that use delayed expansion, that is, that takes the value of variables that were modified inside IF or FOR commands by enclosing their names in exclamation-marks.

If you enable this expansion in a script that does not require it, the script behaves different only if it contains names enclosed in exclamation-marks !LIKE! !THESE!. Usually the name is just erased, but if a variable with the same name exist by chance, then the result is unpredictable and depends on the value of such variable and the place where it appears.

The SETLOCAL part is REQUIRED in just a few specialized (recursive) programs, but is commonly used when you want to be sure to not modify any existent variable with the same name by chance or if you want to automatically delete all the variables used in your program. However, because there is not a separate command to enable the delayed expansion, programs that require this must also include the SETLOCAL part.

农村范ル 2024-11-26 14:53:20

一个真正的问题经常存在,因为当该批处理文件完成时,内部设置的任何变量都不会被导出。所以它不可能出口,这给我们带来了问题。结果,我只是将注册表设置为始终使用延迟扩展(我不知道为什么它不是默认值,可能是速度或遗留兼容性问题。)

A real problem often exists because any variables set inside will not be exported when that batch file finishes. So its not possible to export, which caused us issues. As a result, I just set the registry to ALWAYS used delayed expansion (I don't know why it's not the default, could be speed or legacy compatibility issue.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文