批量从数组元素中提取文件名
Extracting file name from array element in batch
我有一个这样的环境变量
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
代码有什么问题,为什么?
打开命令提示符 window、运行 set /?
并阅读输出帮助页面,解释何时以及如何在命令的代码块中使用延迟扩展 IF 和 FOR.
批处理文件中的 %%
被解释为文字百分号,这就是为什么在命令提示符 window 中直接执行的命令中的循环变量必须只指定一个百分号的原因而批处理文件中的相同循环在引用循环变量时需要两个百分号。
当 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 table.
中的下一个字符
2>nul
用于通过重定向到设备 NUL 如果在任何情况下都没有定义名称以 BINARY[
开头的环境变量。重定向运算符 >
必须使用 ^
转义,否则命令处理器将退出此行的批处理,因为 2>nul
导致 FOR[=109 上的语法错误=] 这个位置的命令行。
注意:由于命令SET按字母排序输出,环境变量BINARY[10]
在[=35=之后输出] 以及 BINARY[1]
和 BINARY[2]
之前。因此,如果顺序很重要,则需要第一个批处理解决方案,或者环境变量是用方括号中的数字创建的,所有数字的位数都相同,前导零,即 00000、00001、...、00002、00010、00011、...。 ..
要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
另请参阅有关 Using command redirection operators 的 Microsoft 文章。
我有一个这样的环境变量
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
代码有什么问题,为什么?
打开命令提示符 window、运行 set /?
并阅读输出帮助页面,解释何时以及如何在命令的代码块中使用延迟扩展 IF 和 FOR.
%%
被解释为文字百分号,这就是为什么在命令提示符 window 中直接执行的命令中的循环变量必须只指定一个百分号的原因而批处理文件中的相同循环在引用循环变量时需要两个百分号。
当 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 table.
2>nul
用于通过重定向到设备 NUL 如果在任何情况下都没有定义名称以 BINARY[
开头的环境变量。重定向运算符 >
必须使用 ^
转义,否则命令处理器将退出此行的批处理,因为 2>nul
导致 FOR[=109 上的语法错误=] 这个位置的命令行。
注意:由于命令SET按字母排序输出,环境变量BINARY[10]
在[=35=之后输出] 以及 BINARY[1]
和 BINARY[2]
之前。因此,如果顺序很重要,则需要第一个批处理解决方案,或者环境变量是用方括号中的数字创建的,所有数字的位数都相同,前导零,即 00000、00001、...、00002、00010、00011、...。 ..
要了解使用的命令及其工作原理,请打开命令提示符 window,在其中执行以下命令,并仔细阅读为每个命令显示的所有帮助页面。
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
另请参阅有关 Using command redirection operators 的 Microsoft 文章。