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

时间:2014-08-28 12:20:38

标签: 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 -i %%a  %fName:~0,-3%.ttf

但由于上述问题导致其失败)

有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:1)

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

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

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

并且set /A仅用于算术运算

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

已修改以适应评论

虽然for命令能够执行命令(在OP代码中,dir...),检索其输出,然后迭代此输出中的行,该命令的原始原因是迭代一组文件。在此表单中,代码可以写为

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

现在,for命令可替换参数将遍历指定的文件集。 (执行for /?以获取所有命令选项的列表。)

但正如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)。

@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%]