带括号的块中的所有代码都一次性解析。使用百分比的正常变量扩展发生在解析时。因此,如果您在块中设置变量,则无法使用正常扩展访问该值,因为该值将是您进入块之前存在的值。
你有上述情况。有两种经典的方法可以解决这个问题。
1)您可以使用 CALL 并将百分比加倍。CALL 解决了这个问题,因为被调用行的正常扩展发生了两次——一次是整个块,一次是在执行该行之前,但在块中的前几行已经执行之后。第一个扩展将双百分比转换为单百分比,第二个扩展实际上扩展了变量。
我不喜欢这个解决方案,因为它很慢,还因为 CALL 会导致引用^
字符出现问题 - 它们加倍。
您可以在同一命令上使用多个 CALL。每次通话都要求百分比翻倍。所以一个 CALL 需要 2%,两个 CALL 需要 4%,三个 CALL 需要 8%,等等。
2)我认为首选的解决方案是使用延迟扩展。它速度更快,而且当您使用延迟扩展时,您不必担心转义或引用特殊字符,如&
, |
,等。延迟扩展正如它所说的那样 - 直到执行该行之前变量才被扩展。延迟扩展必须先启用,然后才能使用。在批处理文件中,您可以使用.>
<
setlocal enableDelayedExpansion
延迟扩展可能发生的一个问题是,如果 FOR 变量包含!
并且在扩展时启用了延迟扩展,则它们会损坏。这通常可以通过在循环中打开和关闭延迟扩展来解决。
如果您HELP SET
从命令提示符键入,您将很好地描述在代码块中扩展变量的问题,以及延迟扩展如何提供帮助。描述从单词的一半开始Finally, support for delayed environment variable expansion...
。
注意 - 在 SET /A 计算中使用时,您不需要扩展变量。SET /A 将在执行时自动扩展值。未定义的变量被视为零。
在您的代码中,您可以简单地使用set /a add=add+1
但是还有一种更简单的速记方式——你可以使用+=
操作符:set /a add+=1
。
这是无需使用 CALL 即可编写代码的另一种方式。代码未经测试,但我认为我做对了。
@echo off
setlocal disableDelayedExpansion
cd "%~dp0"
md newfolder
set add=0
for /f "usebackq eol=: delims=" %%F in ("list.txt") do (
set /a add+=1
set "file=%%F"
setlocal enableDelayedExpansion
set "addx=00!add!"
copy "!file!" "newfolder\!addx:~-3!_!file!"
endlocal
)
pause
我显式初始化add
为 0,因为它可能已经设置为一个值。如果您知道它未定义或已设置为 0,则不需要初始化。
您的 FOR 循环正在处理文件名,并且!
在文件名中有效。这就是我在循环中打开和关闭延迟扩展的原因 - 我不希望!
在扩展时损坏文件名%%F
。文件名也可以以开头;
(尽管不太可能)。如果是这样,则 FOR 将跳过该文件,因为默认 EOL 字符是;
. 文件永远不能以 . 开头:
,所以我喜欢将 EOL 设置为:
。
我将 SETLOCAL 放在顶部附近,以便在批处理文件完成后环境变量定义不会持续存在。