Batch file 在批处理中为循环设置变量

Batch file 在批处理中为循环设置变量,batch-file,for-loop,variables,cmd,Batch File,For Loop,Variables,Cmd,在过去的两天里,我一直在和一段代码做斗争。 在这种情况下,我无法在for循环中设置变量。 我想为一个变量分配一个文件名以进行字符串操作 echo off for /f %%a IN ('dir /b *_ah.ttf') DO ( set /a fName=%%~na echo %fName% ) 当我echo fName变量时,我只得到最后一个文件名,重复循环计数的次数 (我想将此变量作为参数传递给某个批处理文件,如下所示 ttfhnt --strong-stem-width=D -

在过去的两天里,我一直在和一段代码做斗争。 在这种情况下,我无法在for循环中设置变量。 我想为一个变量分配一个文件名以进行字符串操作

echo off
for  /f  %%a IN ('dir /b *_ah.ttf') DO (
set /a fName=%%~na 
echo %fName% 
)
当我
echo fName
变量时,我只得到最后一个文件名,重复循环计数的次数

(我想将此变量作为参数传递给某个批处理文件,如下所示

ttfhnt --strong-stem-width=D -i %%a  %fName:~0,-3%.ttf
但由于上述问题,其失败)


有人能帮我吗?

当cmd解析器读取一行或一块行(括号内的代码)时,在开始执行代码之前,所有变量读取都将替换为变量内的值。如果块中代码的执行改变了变量的值,则无法从同一块内看到该值,因为变量上的读取操作不存在,因为它已被变量中的值替换

在多个命令与
&
串联的行中也可以看到相同的行为。该行被完全解析,然后执行。如果第一个命令更改变量的值,则后面的命令不能使用此更改的值,因为读取操作将替换

要解决这个问题,您需要启用延迟扩展,并且在需要时,将语法从
%var%
更改为
!瓦尔,向解析器指示读取操作需要延迟到执行命令为止

set/A
仅用于算术运算

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

虽然
for
命令能够执行命令(在操作代码中,
目录…
),检索其输出,然后迭代该输出中的行,但该命令的原始原因是迭代一组文件。在这种形式下,代码可以写成

setlocal enabledelayedexpansion
for  %%a IN ("*_ah.ttf") DO (
    set "fName=%%~na"
    echo "!fName!" "!fName:~0,-3!"
)
现在,
命令可替换参数将迭代指定的文件集。(执行
获取/?
获取所有命令选项的列表)

但正如foxidrive指出的那样,延迟扩展的问题在于感叹号。在没有延迟扩展的情况下,它们是另一个正常字符,但是在延迟扩展的情况下,当包含它们的值被赋值/回显时,它们经常成为一个问题

快速测试

@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
将显示

---------------------
test=this is a test!
---------------------
delayed : this is a test!
normal  : this is a test
for     : this is a test
显然,当该值是文件名时,此行为将使代码查找或不查找文件

根据具体情况,可以使用不同的解决方案,但通常涉及延迟扩展行为的激活/取消激活(注意,
endlocal
会从先前的
setlocal
中删除环境变量中的任何更改)


+我只是在这里评论一下,文件名包含
将因扩展延迟而失败。如果文件名只有一个
则可以用另一种方法处理。非常棒的MC ND,它可以完美地工作。非常感谢您的快速回答和详细解释。我会把你的答案读几遍,以适应我的大脑。顺便说一句,感谢speising的细致观察。@speising出于某种原因(*_ah.ttf)对我不起作用。但无论如何,谢谢你的评论。斯皮辛的评论是准确的——如果你按照他说的去做,效果会很好。我从来没想到会这么复杂。你的回答比我的任务要求的要有用得多。我将尝试在脚本中实现这个逻辑。干得好。谢谢@foxidrive,是的,他一定是对的,但我似乎不能正确使用它。DOS中没有用于/f的
。它仅在Windows cmd中可用。他们非常不同
@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%]