从数组元素中批量提取文件名 [英] Extracting file name from array element in batch

查看:118
本文介绍了从数组元素中批量提取文件名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个这样的环境变量

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆