views:

3169

answers:

4

I have a batch file which initializes variables via SET inside a for loop, for a set of files on disk:

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

  echo In loop %TMPFILE%
)

echo End loop %TMPFILE%

when I run this in a brand new command shell (without TMPFILE defined) the In loop echo is empty, but the end loop echo is not.

When I run a second time, its already set, and outputs its value, ignoring the set until the loop closes.

Ideas why this is, and what the workaround is?

+2  A: 

That's because the ( ) block is parsed only once, it substitutes %TMPFILE% before it runs your loop.

chris
Thanks, I just saw setlocal ENABLEDELAYED EXPANSION
theschmitzer
A: 

on for the record, corrected script looks like this:

setlocal ENABLEDELAYEDEXPANSION

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

echo In loop !TMPFILE! )

echo End loop %TMPFILE%

Thanks chris for your help

theschmitzer
+2  A: 

It because environment variables are substituted when the command is read. For the following command:

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

the entire command (from for to the closing parenthesis) is read and substituted before execution.

You need to use delayed expansion, such as with:

@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

When you enable delayed expansion, the "%" markers still act as before but you can use the "!" markers to do the delayed expansion.

paxdiablo
A: 

You can also use CALL SET instead of delayed expansion.

George V. Reilly