简体   繁体   English

批量在for循环中设置变量

[英]Setting up variable in for loop in batch

I am fighting with little piece of code for last two days. 最近两天,我只用很少的代码就可以解决问题。 In this I am not able to set variable in a for loop. 在这种情况下,我无法在for循环中设置变量。 I want to assign a filename to a variable for string manipulation. 我想将文件名分配给变量以进行字符串操作。

echo off
for  /f  %%a IN ('dir /b *_ah.ttf') DO (
set /a fName=%%~na 
echo %fName% 
)

When I echo fName variable I get only last filename repeatedly number of times for for loop count. 当我echo fName变量时,我仅重复获得最后一个文件名的次数,用于for循环计数。

(I want to pass this variable as an argument to some batch file as follows (我想将此变量作为参数传递给某些批处理文件,如下所示

ttfhnt --strong-stem-width=D -i %%a  %fName:~0,-3%.ttf

but its failing due to above problem) 但由于上述问题而失败)

Can somebody help me please? 有人可以帮我吗?

When the cmd parser reads a line or a block of lines (the code inside the parenthesis), all variable reads are replaced with the value inside the variable before starting to execute the code. 当cmd解析器读取一行或一行行(括号内的代码)时,所有读取的变量都将替换为变量内的值, 然后再开始执行代码。 If the execution of the code in the block changes the value of the variable, this value can not be seen from inside the same block, as the read operation on the variable does not exist, as it was replaced with the value in the variable. 如果块中代码的执行更改了变量的值,则无法从同一块内部看到此值,因为不存在对变量的读取操作,因为已将其替换为变量中的值。

This same behaviour is seen in lines where several commands are concatenated with & . 在将多个命令与&串联的行中可以看到相同的行为。 The line is fully parsed and then executed. 该行被完全解析,然后执行。 If the first commands change the value of a variable, the later commands can not use this changed value because the read operation replace. 如果前几个命令更改了变量的值,则后几个命令将不能使用此更改的值,因为读取操作将被替换。

To solve it, you need to enable delayed expansion, and, where needed, change the syntax from %var% to !var! 要解决此问题,您需要启用延迟扩展,并在需要时将语法从%var%更改为!var! , indicating to the parser that the read operation needs to be delayed until the execution of the command. ,向解析器指示读取操作需要延迟直到命令执行为止。

And set /A is only used for arithmetic operations set /A仅用于算术运算

setlocal enabledelayedexpansion
for  /f "delims=" %%a IN ('dir /b *_ah.ttf') DO (
    set "fName=%%~na"
    echo "!fName!" "!fName:~0,-3!"
)

edited to adapt to comments 编辑以适应评论

While for command is able to execute a command (in the OP code, the dir... ), retrieve its output and then iterate over the lines in this output, the original reason for the command is to iterate over a set of files. 尽管for命令能够执行命令(在OP代码中, dir... ),检索其输出然后在此输出中的行上进行迭代,但命令的原始原因是在一组文件上进行迭代。 In this form, the code can be written as 以这种形式,代码可以写成

setlocal enabledelayedexpansion
for  %%a IN ("*_ah.ttf") DO (
    set "fName=%%~na"
    echo "!fName!" "!fName:~0,-3!"
)

Now, the for command replaceable parameter will iterate over the indicated set of files. 现在, for命令的replaceable参数将遍历指示的文件集。 (execute for /? for a list of all the command options). for /?执行for /?获取所有命令选项的列表)。

But as foxidrive points, the problem with delayed expansion are the exclamation signs. 但是作为foxidrive点,扩展延迟的问题是惊叹号。 Without delayed expansion, they are another normal character, but with delayed expansion they frequently become a problem when a value containig them is assigned/echoed. 没有延迟的扩展,它们是另一个正常的字符,但是在延迟的扩展中,当包含/分配它们的值时,它们经常成为问题。

A quick test 快速测试

@echo off
    setlocal enabledelayedexpansion

    set "test=this is a test^!"
    echo ---------------------
    set test
    echo ---------------------
    echo delayed : !test!
    echo normal  : %test%
    for /f "delims=" %%a in ("!test!") do echo for     : %%a

Will show 将会呈现

---------------------
test=this is a test!
---------------------
delayed : this is a test!
normal  : this is a test
for     : this is a test

Obviously when the value is a file name, this behaviour will make the code find or not the file. 显然,当该值是文件名时,此行为将使代码查找或不查找文件。

Depending on the case different solutions can be used, but usually it involves the activation / desactivation of the delayed expansion behaviour (beware, the endlocal removes any change in environment variables from the previous setlocal ). 根据情况的不同,可以使用不同的解决方案,但通常涉及延迟扩展行为的激活/取消激活(请注意, endlocal会从先前的setlocal删除环境变量的任何更改)。

@echo off
    setlocal enabledelayedexpansion

    set "test=this is a test^!"
    echo ---------------------
    set test
    echo ---------------------
    echo delayed : !test!

    rem Commuted to no delayed expansion
    setlocal disabledelayedexpansion
    echo normal  : %test%
    endlocal

    rem Cancelled the initial enable delayed expansion
    for /f "delims=" %%a in ("!test!") do endlocal & echo for     : %%a

    rem The last endlocal has removed the changes to the variable
    echo no data : [%test%]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM