现在用延迟扩展重复此操作:复制代码
- @echo off
- SETLOCAL
- Set "_var=first"
- Set "_var=second" & Echo %_var%
输出:first
%_var%的值在被 Set 命令更改之前被读入内存。
FOR 循环复制代码
- @echo off
- SETLOCAL EnableDelayedExpansion
- Set "_var=first"
- Set "_var=second" & Echo %_var% !_var!
这将输出:first second
!_var!的值变量被尽可能晚地替换,而%_var% 变量的工作方式与以前一样。
使用 FOR 循环时,延迟变量扩展通常很有用,通常整个 FOR 循环都会被视为单个命令,即使它跨越批处理脚本的多行。
这是 FOR 循环的默认行为:
复制代码
- @echo off
- setlocal
- :: 计数到 5 将结果存储在变量
- set _tst=0
- FOR /l %%G in (1,1,5) Do (echo [%_tst%] & set /a _tst+=1)
- echo Total = %_tst%
C:> demo_batch.cmd
[0]
[0]
[0]
[0]
[0]
Total = 5
请注意,当 FOR 循环完成时,我们得到了正确的总计,因此变量正确地递增,但在循环的每次迭代期间,即使我们设置新值,变量也会顽固地显示其初始值 0。
与EnableDelayedExpansion相同的脚本给出相同的最终结果,但也显示中间值:
复制代码
- @echo off
- setlocal EnableDelayedExpansion
- :: 计数到 5 将结果存储在变量
- set _tst=0
- FOR /l %%G in (1,1,5) Do (echo [!_tst!] & set /a _tst+=1)
- echo Total = %_tst%
使用 %var% 和 !var!C:\>demo_batch.cmd
[0]
[1]
[2]
[3]
[4]
Total = 5
与EnableDelayedExpansion相同的脚本给出相同的最终结果,但也显示中间值:
请注意,在 for 循环中我们使用!variable! 而不是%variable%。
另一种编写方法是调用子例程,因为这会跳出循环,因此不需要延迟扩展
复制代码
- @echo off
- setlocal
- :: 计数到 5 将结果存储在变量
- set _tst=0
- FOR /l %%G in (1,1,5) Do (call :sub %%G)
- echo Total = %_tst%
- goto :eof
- :sub
- echo [%1] & set /a _tst+=1
- goto :eof
C:\> demo_batch.cmd
[1]
[2]
[3]
[4]
[5]
Total = 5
通过延迟扩展,单个变量可以保存两个值:其他效果 - 标点符号
复制代码
- @echo off
- Setlocal EnableDelayedExpansion
- Set "_var=Old"
- For /L %%G in (1,1,3) Do (
- Set "_var=New"
- Echo [%_var%] is now [!_var!]
- )
输出:
[Old] is now [New]
[Old] is now [New]
[Old] is now [New]
请注意,变量在循环的每次迭代中恢复为旧值,不需要 Set _var=%_var%
这是因为 FOR 循环的每次迭代将启动一个新的批处理文件上下文以及任何指定的参数。
因为 DelayedExpansion 稍后会扩展变量,这意味着表达式中的任何转义字符(^) 和重定向字符都将在变量扩展之前进行计算,这非常有用:更多示例
复制代码
- @echo off
- Setlocal
- Set _html=Hello^>World
- Echo %_html%
在上面,Echo 命令将创建一个名为“world”的文本文件 - 不完全是我们想要的!这是因为变量在解析时扩展,因此最后一行正在执行Echo Hello > World并且 > 字符被解释为重定向运算符。
如果我们现在尝试使用EnableDelayedExpansion进行同样的操作:
复制代码
- Setlocal EnableDelayedExpansion
- Set _html=Hello^>World
- Echo !_html!
通过延迟扩展,变量(包括>)仅在执行时扩展,因此>字符永远不会被解释为重定向运算符。
这使得在变量中使用 HTML 和 XML 格式的字符串成为可能。
当启用延迟扩展并且一行中至少存在一个感叹号时,任何插入符号都将被解释为转义符,因此将从输出中消失:
复制代码
- Setlocal EnableDelayedExpansion
- Echo "Hello^World"
- Echo "Hello^World!"
上面输出:
"Hello^World"
"HelloWorld"
即使您将插入符号 ^^ 加倍(通常用作转义符),或者在感叹号之前添加转义符,行中任何位置存在感叹号仍然会产生这种效果。
在 FOR 命令中设置并回显相同的变量:使用延迟变量扩展时的一些意外行为
复制代码
- Setlocal EnableDelayedExpansion
- for /f %%G in ("abc") do ( set _demo=%%G & echo !_demo!)
使用另一个变量的值替换variable_name:
复制代码
- @echo off
- setlocal EnableDelayedExpansion
- Set var1=Hello ABC how are you
- Set var2=ABC
- Set result=!var1:%var2%=Beautiful!
- Echo [!result!]
另一种用另一个变量的内容替换命名变量的方法是CALL SET
如果DelayedExpansion与循环一组文件的 FOR 命令结合使用,并且该组中的任何文件有感叹号“!” 在filename中,它将被解释为!variable! 。为什么会有这种行为?
尽管这不是文件名中常用的字符,但它可能会导致脚本失败。发生这种情况是因为参数扩展 (%%P) 发生在延迟扩展阶段尝试解释my!filen!ame.txt之前
当DelayedExpansion在输出为Piped的代码块(括号之间分组的一个或多个命令)内使用时,将跳过变量扩展。 当您使用管道时,管道的两个部分都将在新的 cmd.exe 实例中执行,并且默认情况下这些实例会在禁用延迟扩展的情况下启动。
SET 命令于 1983 年 3 月首次随 MS-DOS 2.0 引入,当时内存和 CPU 非常有限,每行一次变量扩展就足够了。默认行为
大约 16 年后的 1999 年,延迟扩展被引入,当时已经使用早期语法编写了数百万个批处理文件。保留立即扩展作为默认值保留了与现有批处理文件的向后兼容性。
如果从头开始,这不是任何人都会设计语言的方式,PowerShell 的行为确实是这样的:
PS C:\> $demo = "First"
PS C:\> $demo = "Second" ; echo $demo
Second
默认情况下禁用 EnableDelayedExpansion。还可以通过使用/v相关命令论坛讨论- EnableDelayedExpansion(非常感谢 Jeb 和 Aacini 澄清了很多观点)。
开关 启动CMD来启用 EnableDelayedExpansion 。
开启延迟扩展后,可以使用SETLOCAL DisableDelayedExpansion再次关闭延迟扩展
EnableDelayedExpansion 可以在 HKLM 或 HKCU 下的注册表中设置为默认值:
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor]
"DelayedExpansion"= (REG_DWORD)
1=enabled 0=disabled (default)
不建议更改此默认值。
除非您运行的每个批处理脚本都以适当的SETLOCAL DisableDelayedExpansion或SETLOCAL EnableDelayedExpansion命令开始,否则更改默认值可能会破坏某些脚本。
axiang117 发表于 2024-3-22 11:07
看了半天也没看明白,可能是我太笨了
欢迎光临 无忧启动论坛 (http://wuyou.net/) | Powered by Discuz! X3.3 |