从数组元素中批量提取文件名 [英] 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
代码有什么问题,为什么?
打开命令提示符窗口,运行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
的第一个等号之后的所有内容,循环变量J
是ASCII表中的下一个字符.
2>nul
用于通过将命令 SET 重定向到设备 NUL 来抑制命令 SET 输出到 STDERR 的错误消息在任何情况下,环境变量都以BINARY[
开头的名称定义.重定向操作符>
必须用^
进行转义,否则命令处理器将由于2>nul
退出此行的批处理,这会导致 FOR 命令行在此位置出现语法错误.
注意:由于命令 SET 按字母顺序排序输出,因此环境变量BINARY[10]
在BINARY[0]
之后,在BINARY[1]
和BINARY[2]
之前输出.因此,如果顺序很重要,则需要第一批解决方案,或者使用方括号中具有数字的环境变量创建数字,这些数字都具有前导零的相同数字,即00000、00001,...,00022、00010、00011等. ..
要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面.
-
call /?
-
echo /?
-
endlocal /?
-
for /?
-
goto /?
-
if /?
-
set /?
-
setlocal /?
另请参见有关使用命令重定向运算符的Microsoft文章./p>
I have an environment variable like this
set BINARY[0]=C:\binary.bin
From which I'm trying to extract the full file name
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 ...
However for some reason, it tries to do:
set FNAME=%BINARY[0]%
instead of
set FNAME=binary.bin
What's wrong with the code and why?
Open a command prompt window, run set /?
and read the output help pages explaining when and how to use delayed expansion in a code block for the commands IF and FOR.
%%
in a batch file is interpreted as literal percent character which is the reason why a loop variable in a command executed directly in a command prompt window must be specified with just one percent sign while the same loop in a batch file requires two percent signs on referencing the loop variable.
When the Windows command processor encounters an opening parenthesis which marks the beginning of a command block, it searches for the matching closing parenthesis and replaces all environment variables references with syntax %VariableName%
by the current value of the variable or nothing in case of variable does not exist. Then after the entire command block was parsed the IF or FOR is executed and used is once or more times the already preprocessed command block.
You could use
@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
which outputs
C:\binary0.bin
FNAME=binary0.bin
C:\binary1.bin
FNAME=binary1.bin
The command line
call echo %%BINARY[%x%]%%
is something special. This line is preprocessed before execution of command IF to
call echo %BINARY[0]%
respectively on second run to
call echo %BINARY[1]%
By usage of command CALL the single command line is processed like a subroutine or another batch file which means the line is preprocessed once more resulting in execution of
echo C:\binary0.bin
and on second run in execution of
echo C:\binary1.bin
which is the reason why the output is as expected here. But there is no double preprocessing for the environment variable reference in FOR.
Much better would be most likely the following code:
@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
The command set
outputs all variables with their name and equal sign and their values which start with the specified string when there is whether parameter /A
or /P
used and the parameter does not contain an equal sign in an alphabetically sorted list. So the output of
set "BINARY[" 2>nul
as used in the command FOR is
BINARY[0]=C:\binary0.bin
BINARY[1]=C:\binary1.bin
which is processed by the FOR loop which splits each line into two strings based on first occurrence of the equal sign because of tokens=1* delims==
. The first string is the variable name assigned to loop variable I
. And the second string is everything after first equal sign assigned to loop variable J
being the next character in ASCII table.
2>nul
is used to suppress the error message output by command SET to STDERR by redirecting it to device NUL if there is no environment variable defined with a name starting with BINARY[
in any case. The redirection operator >
must be escaped with ^
as otherwise command processor would exit batch processing on this line because of 2>nul
resulting in a syntax error on FOR command line at this position.
Note: Because of alphabetically sorted output by command SET the environment variable BINARY[10]
is output after BINARY[0]
and before BINARY[1]
and BINARY[2]
. So if the order is important, the first batch solution is needed or the environment variables are created with number in square brackets have all same number of digits with leading zeros, i.e. 00000, 00001, ..., 00002, 00010, 00011, ...
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?
And see also Microsoft article about Using command redirection operators.
这篇关于从数组元素中批量提取文件名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!