What Is With This DelayedExpansion Stuff?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
nitt
Posts: 218
Joined: 22 Apr 2011 02:43

What Is With This DelayedExpansion Stuff?

#1 Post by nitt » 01 Jun 2011 19:16

I see a lot of people use "setlocal enableDelayedExpansion" and then they use variable like this: "!var!". I tried that but they seem to work exactly the same of other variables.

What's DelayedExpansion?

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: What Is With This DelayedExpansion Stuff?

#2 Post by dbenham » 01 Jun 2011 19:55

Here is the relevant excerpt from HELP SET

Code: Select all

Delayed environment variable expansion is useful for getting around
the limitations of the current expansion which happens when a line
of text is read, not when it is executed.  The following example
demonstrates the problem with immediate variable expansion:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "%VAR%" == "after" @echo If you see this, it worked
    )

would never display the message, since the %VAR% in BOTH IF statements
is substituted when the first IF statement is read, since it logically
includes the body of the IF, which is a compound statement.  So the
IF inside the compound statement is really comparing "before" with
"after" which will never be equal.  Similarly, the following example
will not work as expected:

    set LIST=
    for %i in (*) do set LIST=%LIST% %i
    echo %LIST%

in that it will NOT build up a list of files in the current directory,
but instead will just set the LIST variable to the last file found.
Again, this is because the %LIST% is expanded just once when the
FOR statement is read, and at that time the LIST variable is empty.
So the actual FOR loop we are executing is:

    for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time.  If delayed variable expansion is enabled, the above
examples could be written as follows to work as intended:

    set VAR=before
    if "%VAR%" == "before" (
        set VAR=after
        if "!VAR!" == "after" @echo If you see this, it worked
    )

    set LIST=
    for %i in (*) do set LIST=!LIST! %i
    echo %LIST%


Dave Benham

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

Re: What Is With This DelayedExpansion Stuff?

#3 Post by orange_batch » 01 Jun 2011 22:32

Or simply, try this example:

Code: Select all

set counter=0
for /l %%a in (1,1,100) do (
set /a counter+=1
set myvar=%counter%
)
echo:%myvar%
echo:%counter%

myvar = 0, counter = 100. That's because Command Prompt expands %var%s to their value BEFORE execution, at the time the code is being read/parsed/interpreted (so it effects anything within parentheses, as the whole block is read before processing). It sees this:

Code: Select all

set counter=0
for /l %%a in (1,1,100) do (
set /a counter+=1
set myvar=0
)
echo:%myvar%
echo:%counter%

Delayed expansion is just that. It expands at the moment the code is executed. Command Prompt sees this as-is:

Code: Select all

setlocal enabledelayedexpansion
set counter=0
for /l %%a in (1,1,100) do (
set /a counter+=1
set myvar=!counter!
)
echo:%myvar%
echo:%counter%

myvar is now the proper value 100.

Delayed expansion allows for some other tricks too, like dynamic variables, without the requirement for the CALL expansion trick (not gonna explain that at the moment, but it allows a form of %% delayed expansion without !! enabledelayedexpansion). viewtopic.php?f=3&t=1486

Code: Select all

for /f "delims=" %%a in (textfile.txt) do (
set /a counter+=1
set log!counter!=%%a
)
for /l %%a in (1,1,%counter%) do (
echo:!log%%a!
)

Now you've logged each line to an "array" of sorts, log#, from log1 to log(the value of counter).

Post Reply