我有一个像这样的环境变量
set BINARY[0]=C:\binary.bin
我正试图从中提取完整的文件名
set "x=0"
:binloop
if defined BINARY[%x%] (
call echo %%BINARY[%x%]%%
FOR %%i IN ("%%BINARY[%x%]%%") DO (
set FNAME=%%~nxi
)
set /a "x+=1"
GOTO binloop
)
rem ...
但出于某种原因,它试图这样做:
set FNAME=%BINARY[0]%
而不是
set FNAME=binary.bin
代码有什么问题?为什么?
答案 0 :(得分:2)
打开命令提示符窗口,运行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
命令set
输出所有变量及其名称和等号,以及当使用参数/A
或/P
时参数不符合指定字符串的值在按字母顺序排序的列表中包含等号。
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 /?
另请参阅Microsoft关于Using command redirection operators的文章。