打开命令提示符窗口,运行 set /? 并阅读输出帮助页面,说明何时以及如何在代码块中为命令 IF 和 FOR 使用延迟扩展>.
批处理文件中的%% 被解释为文字百分比字符,这就是为什么在命令提示符窗口中直接执行的命令中的循环变量必须仅用一个百分号指定,而批处理文件中的相同循环引用循环变量时需要两个百分号。
当 Windows 命令处理器遇到一个标记命令块开始的左括号时,它会搜索匹配的右括号并将所有使用语法 %VariableName% 的环境变量引用替换为变量的当前值或不替换以防万一的变量不存在。然后在解析整个命令块之后,执行 IF 或 FOR 并使用已经预处理的命令块一次或多次。
你可以使用
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BINARY[1]=C:\binary1.bin"
set "BINARY[0]=C:\binary0.bin"
set "x=0"
:binloop
if defined BINARY[%x%] (
call echo %%BINARY[%x%]%%
for %%i in ("!BINARY[%x%]!") do (
set FNAME=%%~nxi
set FNAME
)
set /a "x+=1"
goto binloop
)
endlocal
哪个输出
C:\binary0.bin
FNAME=binary0.bin
C:\binary1.bin
FNAME=binary1.bin
命令行
call echo %%BINARY[%x%]%%
有点特别。此行在执行命令 IF 到
之前进行了预处理
call echo %BINARY[0]%
分别在第二次运行时
call echo %BINARY[1]%
通过使用命令CALL,单个命令行像子程序或另一个批处理文件一样被处理,这意味着该行被再次预处理,导致执行
echo C:\binary0.bin
并在第二次运行时执行
echo C:\binary1.bin
这就是这里的输出符合预期的原因。但是FOR中的环境变量引用没有双重预处理。
最好是以下代码:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "BINARY[1]=C:\binary1.bin"
set "BINARY[0]=C:\binary0.bin"
for /F "tokens=1* delims==" %%I in ('set "BINARY[" 2^>nul') do (
set "FNAME=%%~nxJ"
set FNAME
)
endlocal
当参数/A或/P被使用且参数中不包含等号时,命令set输出所有变量及其名称和等号以及以指定字符串开头的值按字母顺序排列的列表。所以
的输出
set "BINARY[" 2>nul
在命令中使用 FOR 是
BINARY[0]=C:\binary0.bin
BINARY[1]=C:\binary1.bin
由 FOR 循环处理,该循环根据 tokens=1* delims== 的第一次出现等号将每行拆分为两个字符串。第一个字符串是分配给循环变量I 的变量名。第二个字符串是分配给循环变量J的第一个等号之后的所有内容,是ASCII表中的下一个字符。
2>nul 用于抑制命令 SET 到 STDERR 输出的错误消息,如果没有,则将其重定向到设备 NUL在任何情况下,环境变量的名称都以BINARY[ 开头。重定向运算符> 必须用^ 转义,否则命令处理器将退出此行的批处理,因为2>nul 导致FOR 命令行在此位置出现语法错误。
注意:由于命令 SET 按字母顺序输出,环境变量BINARY[10] 在BINARY[0] 之后和BINARY[1] 和BINARY[2] 之前输出。因此,如果顺序很重要,则需要第一个批处理解决方案,或者使用方括号中的数字创建环境变量,它们的数字都相同,前导零,即 00000, 00001, ..., 00002, 00010, 00011, 。 ..
要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
另请参阅有关 Using command redirection operators 的 Microsoft 文章。