以批处理环境中执行的这一系列简单命令为例:
>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!
它输出以下内容:
>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!
因此它显然不会扩展到其值。我该怎么做?
答案1
资料来源:
第 5 阶段在Windows 命令解释器(CMD.EXE)如何解析脚本?
延迟扩展:仅当延迟扩展处于打开状态时,命令才不处于管道两侧的括号块,并且该命令不是“裸”批处理脚本(脚本名称不带括号、CALL、命令连接或管道)。
- 每个命令的标记都会被独立解析以进行延迟扩展。
- 大多数命令解析两个或多个标记 - 命令标记、参数标记和每个重定向目标标记。
- FOR 命令仅解析 IN 子句标记。
- IF 命令仅解析比较值 - 一个或两个,取决于比较运算符。
- 对于每个解析的标记,首先检查它是否包含任何
!
。如果没有,则标记未解析 - 这对于^
字符很重要。如果标记确实包含!
,则从左到右扫描每个字符:- 如果是插入符号 (
^
),则下一个字符没有特殊含义,插入符号本身将被删除 - 如果是感叹号,则搜索下一个感叹号(不再观察到插入符号),扩展为变量的值。
- 连续的开口
!
被折叠成一个!
- 任何剩余的未配对
!
将被删除
- 连续的开口
- 在这个阶段扩展 vars 是“安全的”,因为不再检测到特殊字符(甚至
<CR>
或<LF>
) - 如需更完整的解释,请阅读 dbenham 的后半部分 同一线程-感叹号阶段
- 如果是插入符号 (
5.3)管道加工阶段:仅当命令位于管道的两侧时,
管道的每一侧才会独立且异步地处理。
- 如果命令是 cmd.exe 的内部命令,或者它是一个批处理文件,或者它是一个带括号的命令块,那么它将通过 在新的 cmd.exe 线程中执行
%comspec% /S /D /c" commandBlock"
,因此命令块会获得阶段重新启动,但这次是在命令行模式下。- 如果是带括号的命令块,则所有
<LF>
前后带有 的命令都转换为<space>&
。其他的<LF>
都被剥离。
- 如果是带括号的命令块,则所有
- 这是管道命令处理的结束。
- 看https://stackoverflow.com/q/8192318/1012053有关管道解析和处理的更多信息
阶段5.5)执行重定向:现在执行在第 2 阶段发现的任何重定向。
- 第 4 阶段和第 5 阶段的结果可能会影响第 2 阶段发现的重定向。
- 如果重定向失败,则命令的剩余部分将被中止。请注意,重定向失败不会将 ERRORLEVEL 设置为 1,除非
||
使用。
- 在你的命令行使用
cmd.exe /v:on /c
set ar[0]=orange
set ar[1]=apple
set ar[2]=banana
for %i in (0,1,2) do cmd.exe /v:on /C"echo !ar[%i]!
- 在你的蝙蝠/命令文件无需声明
setlocal enabledelayedexpansion
,您还可以使用cmd.exe /v:on /c "command & command | command || command..."
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %%i in (0,1,2)do cmd /v /c "echo\ !ar[%%i]!"
@echo off
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
setlocal enabledelayedexpansion
for %%i in (0,1,2)do echo\ !ar[%%i]!
enndlocal
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
for %%i in (0,1,2)do %ComSpec% /v:on /c"echo !ar[%%i]!"
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana"
setlocal enabledelayedexpansion && for %%i in (0,1,2)do echo\ !ar[%%i]!
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off
set "ar[0]=orange" && set "ar[1]=apple" && set "ar[2]=banana"
for %%i in (0,1,2)do <con: %ComSpec% /v:on /c"echo !ar[%%i]!"
call <con: rem./ && %__APPDIR__%timeout.exe /t -1 && endlocal
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana"
for %i in (0,1,2)do for %i in (0,1,2)do <con: call echo %ar[%i]%
for %i in (0,1,2) do %ComSpec% /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /c "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/recho !ar[%i]!
for %i in (0,1,2) do %ComSpec%/v/cecho !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!
for %i in (0,1,2) do cmd/v/recho !ar[%i]!
for %i in (0,1,2) do cmd/v/cecho !ar[%i]!
进一步阅读:
[√]放 /?
[√]命令 /?
[√]For 循环
[√]For/F 循环
答案2
延迟扩展主要用于将变量值扩展一次以上,尤其是在For循环中。
引自https://ss64.com/nt/delayedexpansion.html
延迟扩展将导致批处理文件中的变量在执行时而不是在解析时扩展,此选项通过 SETLOCAL EnableDelayedExpansion 命令打开。
变量扩展意味着用其值 C:\WINDOWS 替换变量(例如 %windir%)
默认情况下,扩展只会发生一次,在执行每行之前。 !delayed! 扩展在每次执行行时执行,或者在 FOR 循环命令中的每个循环中执行。首先我们看这个例子:
set i=0
for /l %%a in (0,1,10) do (
set /a i=%i%+1
echo %i%
)
这里我们期望输出 1 到 10 的数字。但是,每次它都只输出 0。因为每次变量都会扩展一次,所以值不会改变。
这次我们将尝试延迟扩展:
setlocal enabledelayedexpansion
set i=0
for /l %%a in (0,1,10) do (
set /a i=!i!+1
echo !i!
)
这次我们将得到预期的输出,因为每次我们扩展值时值都会发生变化。
您的代码不起作用,因为您必须setlocal enabledelayedexpansion
在代码开始处添加。
希望有帮助