为什么批处理文件中的延迟扩展在这种情况下不起作用?

Pio*_*ost 3 windows batch-file

这段代码

@echo off
setlocal EnableDelayedExpansion

set myvar=first
set first=second

echo myvar:!myvar!
set myvar=!myvar!
echo myvar:!myvar!
Run Code Online (Sandbox Code Playgroud)

myvar:first
myvar:first
Run Code Online (Sandbox Code Playgroud)

在Windows Vista SP2上.

我预期的输出是

myvar:first
myvar:second
Run Code Online (Sandbox Code Playgroud)

为什么差异以及如何获得理想的效果?

jeb*_*jeb 9

问题是set myvar=!myvar!扩展为set myvar=first,
你用相同的内容设置它,然后你要求echo myvar:!myvar!显示myvar的内容.

我会尝试添加更多解释,即使Aacini和shf301已经回答了这个问题.

两者都显示了!%var%!构造的双重扩展,Aacini解释了为什么它可以工作,以及为什么反转版本%!var!%无法工作.

恕我直言,有四种不同的扩展.
延迟扩展:
正如Aacini所解释的那样,延迟扩展对内容中的任何特殊字符都是安全的(它可以处理从0x01到0xFF的所有字符).

扩展百分比:
扩展百分比无法处理或删除某些字符(即使转义).
它对简单内容很有用,因为它可以在endlocal屏障后扩展变量.

setlocal
set "myVar=simple content"
(
endlocal
set result=%myVar%
)
Run Code Online (Sandbox Code Playgroud)

FOR-Loop-Parameters扩展:
如果禁用延迟扩展,则是安全的,否则延迟扩展阶段在%% a变量扩展后执行.
它可能很有用,因为它可以在endlocal屏障后扩展变量

setlocal EnableDelayedExpansion
set "var=complex content &<>!"
for /F "delims=" %%A in ("!var!") DO (
  endlocal
  set "result=%%A"
)
Run Code Online (Sandbox Code Playgroud)

SET扩展:
set var扩展变量,它始终是安全的,并且与延迟扩展模式无关.

Aacini刚刚解释了这个call %%%var%%%结构是如何工作的,我只是想补充一些其他的评论.
call可堆叠,您可以使用其中的许多,并重新启动解析器.

set "var=%%var%%#"
call call call call call echo %var%
Run Code Online (Sandbox Code Playgroud)

结果 %var%######

call有许多缺点/副作用!
每个电话都是双倍的所有插入符号^
你可以说:"嘿,我已经测试了它,我看不到任何加倍"

call call call call echo ^^
Run Code Online (Sandbox Code Playgroud)

结果 ^

不过这是真的,但它主要是隐藏的,因为每次重启都有一个特殊的角色阶段,插入符号会逃脱下一个角色,但你可以看到加倍效果

call call call call echo "^^"^^
Run Code Online (Sandbox Code Playgroud)

结果 "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"^

即使调用扩展重新启动解析器,也不能在任何阶段使用延迟扩展(仅在第一个阶段).

call 如果检测到未转义的特殊字符,则停止工作.

echo you ^& me
call echo you & me
call echo you ^& me
call echo you ^^& me
call echo you ^^^& me
Run Code Online (Sandbox Code Playgroud)

只有第一个结果输出you & me,所有其他结果都失败了.

另一个问题是呼叫速度极慢,call set var=contentset var=content调用慢50倍,原因是呼叫尝试启动外部程序.

@echo off
setlocal
(
   echo echo *** External batch, parameters are '%%*'
) > set.bat
set "var="
call set var=hello
set var
Run Code Online (Sandbox Code Playgroud)

我希望它有点有趣......
如果你想深入了解你可以阅读CALL我,或者更好地避免调用
以及Windows命令解释器(CMD.EXE)如何解析脚本?