在for循环中初始化批处理变量

17

我有一个批处理文件,它在一个for循环中使用SET初始化一组磁盘上的文件的变量:

for %%f in (%MYTARGETDIR%\*config.xml) do (
  SET TMPFILE=%%F.tmp

  echo In loop %TMPFILE%
)

echo End loop %TMPFILE%

当我在全新的命令行窗口中运行此命令(未定义TMPFILE),循环内的echo为空,但循环结束后的echo不为空。

第二次运行时,TMPFILE已经被设置,并输出其值,忽略了直到循环关闭才进行的设置操作。

有什么想法是为什么会这样,以及解决方法是什么?

5个回答

21

记录一下,经过修正后的脚本如下:

setlocal ENABLEDELAYEDEXPANSION

for %%f in (%MYTARGETDIR%\*config.xml) do (

  SET TMPFILE=%%F.tmp

  echo In loop !TMPFILE!
)

echo End loop %TMPFILE%

感谢chris的帮助。


17

这是因为环境变量在命令读取时被替换。对于以下命令:

for %%f in (%mytargetdir%\*config.xml) do (
    set tmpfile=%%f.tmp
    echo In loop %tmpfile%
)

执行前会读取并替换整个命令(从for到右括号)。

你需要使用延迟扩展,例如:

@echo off
    setlocal enableextensions enabledelayedexpansion
    set full=/u01/users/pax
:loop1
    if not "!full:~-1!" == "/" (
        set full2=!full:~-1!!full2!
        set full=!full:~,-1!
        goto :loop1
    )
    echo !full!
    endlocal

当你启用延迟扩展时,"%" 标记仍然像以前一样起作用,但你可以使用 "!" 标记来进行延迟扩展。


9
那是因为 ( ) 块只被解析一次,在运行循环之前它会替换 %TMPFILE%。

1
谢谢,我刚刚看到了setlocal ENABLEDELAYED EXPANSION。 - theschmitzer

6

您还可以使用调用SET而不是延迟扩展。


2
通常,我会使用/e:on和/v:on开关来调用CMD.EXE,以启用命令扩展和延迟变量扩展。然后,我使用的任何批处理脚本都编码为检查是否打开了延迟变量扩展。
这是我第一次听说SETLOCAL需要参数。我通过SETLOCAL /?进行了检查,果然如此!这对我来说是一个时间和代码节省器。
但是,我注意到在SETLOCAL识别ENABLEDELAYEDEXPANSION选项之前,必须在CMD.EXE中启用命令扩展。这是来自SETLOCAL /?输出的信息。
If Command Extensions are enabled SETLOCAL changes as follows:

SETLOCAL batch command now accepts optional arguments:
        ENABLEEXTENSIONS / DISABLEEXTENSIONS
            enable or disable command processor extensions. These
            arguments takes precedence over the CMD /E:ON or /E:OFF
            switches. See CMD /? for details.
        ENABLEDELAYEDEXPANSION / DISABLEDELAYEDEXPANSION
            enable or disable delayed environment variable
            expansion. These arguments takes precedence over the CMD
            /V:ON or /V:OFF switches. See CMD /? for details.

感谢你们提供这个有价值的答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接