这个代码
@echo off setlocal EnableDelayedExpansion set myvar=first set first=second echo myvar:!myvar! set myvar=!myvar! echo myvar:!myvar!
给
myvar:first myvar:first
在Windows Vista SP2上。
我期望的输出是
myvar:first myvar:second
为什么差异以及如何获得预期的效果?
问题是set myvar=!myvar!
扩展set myvar=first
,
你把它设置为相同的内容,然后你问echo myvar:!myvar!
显示myvar的内容。
即使Aacini和shf301已经回答了这个问题,我也会尝试添加更多解释。
两个都显示了!%var%!
的双重扩展!%var%!
构造,并且Aacini解释了为什么它可以工作,为什么反转版本%!var!%
不能工作。
恕我直言,有四个不同的扩展。
延期扩张:
正如Aacini所解释的,延迟扩展对于内容中的任何特殊字符(它可以处理从0x01到0xFF的所有字符)是安全的。
扩展百分比:
扩展百分比不能处理或删除一些字符(即使转义)。
它可以用于简单的内容,因为它可以扩大变量后,一个endlocal
障碍。
setlocal set "myVar=simple content" ( endlocal set result=%myVar% )
FOR-Loop-Parameters扩展:
如果延迟扩展被禁用,则是安全的,否则延迟扩展阶段在扩展%% a变量之后执行。
它可以是有用的,因为它可以扩大变量之后的一个endlocal
障碍
setlocal EnableDelayedExpansion set "var=complex content &<>!" for /F "delims=" %%A in ("!var!") DO ( endlocal set "result=%%A" )
SET扩展:
set var
也是一个变量,它总是安全的,独立于延迟扩展模式。
Aacini刚才解释了如何call %%%var%%%
构造工作,我只想给出一些额外的评论。
call
是可堆叠的,你可以使用其中的很多,每个都重新启动解析器。
set "var=%%var%%#" call call call call call echo %var%
结果到%var%######
但call
有许多缺点/副作用!
每个电话都加上双^
你可以说:“嘿,我已经测试了,我看不到任何加倍”
call call call call echo ^^
结果^
不过这是真的,但是它大部分是隐藏的,因为每个重新开始都有一个特殊的阶段,在这个阶段中,脱离下一个字符,但是你可以看到加倍的效果
call call call call echo "^^"^^
结果"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"^
即使调用扩展重新启动解析器,也不能在任何阶段使用延迟扩展(仅在第一个阶段)。
如果检测到未转义的特殊字符,则call
停止工作。
echo you ^& me call echo you & me call echo you ^& me call echo you ^^& me call echo you ^^^& me
只有第一个结果输出you & me
,其他的都失败了。
另一个问题是调用速度极其缓慢, call set var=content
比set var=content
慢50倍,原因是调用尝试启动外部程序。
@echo off setlocal ( echo echo *** External batch, parameters are '%%*' ) > set.bat set "var=" call set var=hello set var
我希望有一点有趣
如果你想更深入的了解,你可以阅读致电我,或者更好地避免打电话
和Windows命令解释器(CMD.EXE)如何解析脚本?
这个问题与延迟变量扩展没有直接关系,而是需要两个值的扩展:第一个是变量名,第二个是值的取代。 直接的方法是通过在前面的答案中显示的同一行中的两个扩展: set myvar=!%myvar%!
这是有效的,因为%var%扩展是在执行命令行之前完成的,而!var! 稍后在命令执行之前完成扩展(因此是“延迟”名称)。 这意味着%var%扩展可能提供命令的一部分,并可能导致语法错误,但是!var! 不。 例如, if %var%==value ...
如果var为空或者有空格, if !var!==value ...
导致错误,但是if !var!==value ...
永远不会导致语法错误。
值的双重扩展可以通过其他不涉及延迟变量扩展的方式来实现。 例如,我们可以创建一个辅助批处理文件来进行第二次扩展:
echo myvar:%myvar% echo set myvar=%%%myvar%%%> auxiliary.bat call auxiliary echo myvar:%myvar%
先前的方法可以用来进行第三层甚至更深层次的扩展,甚至可以与延迟扩展结合来创建非常复杂的价值管理。 这件事不只是好奇心,而是访问数组元素或链表的关键。 例如:
set month[1]=January set month[2]=February . . . set month[12]=December for /f "tokens=1-3 delims=/" %%a in ("%date%") do echo Today is !month[%%a]! %%b, %%c
你正在做的事情将无法工作 – 延迟扩展只会改变块内变量的变量扩展行为。 它不允许你尝试的别名/嵌套(缺少一个更好的单词)。
set myvar=first
将变量myvar设置为文本“first”。 set first=second
将变量首先设置为文本“second。这两行之间没有链接, myvar
永远不会计算它没有明确设置的内容。
我不相信有什么可以完成你在这里做的。
*编辑*
确定后,看看你的答案,我看到这是如何工作的,你可以得到你想要的输出:
@echo off setlocal EnableDelayedExpansion set myvar=first set first=second echo myvar:%myvar% set myvar=!%myvar%! echo myvar:%myvar%
所以魔法似乎是因为标准和延迟扩展的发生而发生的。 该行set myvar=!%myvar%!
似乎首先由标准扩展器扩展来set myvar=!first!
(如果使用echo on
运行脚本,你会看到这个)。 然后延时扩展器运行并扩展!first
到“秒”并设置myvar
。
我不知道这是否是标准的和延迟的扩展应该如何工作的文档化行为,或者只是一个实现细节(这意味着它可能会在未来破裂)