22

What is meant by "variable expansion"? Does it mean simply "variable definition", or something else?

What happens when I say setLocal EnableDelayedExpansion? Google wasn't clear.

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
  • 2
    http://ss64.com/nt/delayedexpansion.html ; http://www.robvanderwoude.com/variableexpansion.php – npocmaka Aug 15 '14 at 10:07
  • @npocmaka I read these pages. I still don't understand what is meant by 'variable expansion' - does it simply mean 'putting a valeu in a variable'? – Aviv Cohn Aug 15 '14 at 10:53
  • Ok.Check also the jeb's answer here http://stackoverflow.com/questions/17265882/parse-time-vs-execution-time and here http://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/4095133#4095133 – npocmaka Aug 15 '14 at 11:46
  • `help setlocal` at a command prompt provides documentation, as does `setlocal /?`. Does that help? (It reads pretty clearly to me.) – Ken White Aug 15 '14 at 13:05

2 Answers2

28
  • Variable expansion means replace a variable enclosed in % or ! by its value.
  • The %normal% expansion happen just once, before a line is executed. This means that a %variable% expansion have the same value no matters if the line is executed several times (like in a for command).
  • The !delayed! expansion is performed each time that the line is executed.

See this example:

@echo off
setlocal EnableDelayedExpansion
set "var=Original"
set "var=New" & echo Normal: "%var%", Delayed: "!var!"

Output:

Normal: "Original", Delayed: "New"

Another one:

@echo off
setlocal EnableDelayedExpansion
set "var1=Normal"
set "var2=Delayed"
for /L %%i in (1,1,10) do (
   set "var1=%var1% %%i"
   set "var2=!var2! %%i"
)
echo Normal:  "%var1%"
echo Delayed: "%var2%"

Output:

Normal:  "Normal 10"
Delayed: "Delayed 1 2 3 4 5 6 7 8 9 10"

Normal expansion is not necessarily a disadvantage, but depends on the specific situation it is used. For example, in any other programming languages, to exchange the value of two variables you need the aid of a third one, but in Batch it can be done in just one line:

set "var1=%var2%" & set "var2=%var1%"
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • I see. Let me see if I understand: in normal expansion, any place `%var%` is, it's substituted but it's value *during parsing*. Since very line is parsed only once, `%var%` will be the same through every iteration of the loop. With delayed expansion, substituting %var% with it's value happens 'at runtime', while actually executing the line, thus `%var%` is substituted by it's current correct value. Correct? – Aviv Cohn Aug 15 '14 at 14:40
  • Also, should I always just use `!var!`, except for in unusual circumstances? – Aviv Cohn Aug 15 '14 at 14:41
  • 1
    It worth clarifying that in the case of blocks delimited by parentheses (e.g. `if` blocks) the whole block counts as a "line" ([source](https://superuser.com/questions/78496/variables-in-batch-file-not-being-set-when-inside-if)). – OfirD Apr 08 '20 at 11:39
  • @OfirD Yes, normal expansion occurs just before execution of top-level commands, i.e. commands which are not subcommands, whereas delayed expansion occurs just before execution of leaf commands, i.e. non-compound commands. – August Karlstrom Jun 13 '22 at 15:21
9

In batch variables are expanded by enclosing them in percent signs.

set myVariable=Hello world
echo %myVariable%

That means variable expansion.

Compared to other programming languages, batch don't really work with variables.
Normally it works only with the expansion of them.
It works like the macro expansion of C/C++.

So there doesn't exist a string length function to get the length of a variable,
but you can write a function that counts the characters of text.

Explanation of setLocal EnableDelayedExpansion
The normal percent expansion has two disadvantages.

The expansion happens in the moment of the parsing of a line or a block enclosed with parenthesis, not when the block is executed.

Lets see this sample

set var=one

set var=two & echo %var%
echo %var%

The output will be

one
two

As the echo %var% will be expand before the set var=two will be executed. This can get problematic in FOR loops.

And the second disadvantage is that the batch parser will parse the expanded result of the variable.

set var=cat^&dog
echo %var%

var
Unknown command "dog"

But the percent expansion exists since the beginning of MS-Dos (1920 or so).

The DelayedExpansion adds a new expansion character, the exclamation mark !.

But you have to active it first to use it with setlocal EnableDelayedExpansion, this is for compatibility reasons to old programs.

setlocal EnableDelayedExpansion
set var=one
set var=two & echo !var!
set var=cat^&dog
echo !var!

two
cat&dog

So this solves both problems of the percent expansion.

Delayed Expansion on the command line
You can't enable it by setlocal EnableDelayedExpansion, on the command line it has no effect at all.
But you can use cmd /v:on

set "var=Cat & dog" & cmd /V:on /c echo !var!
jeb
  • 78,592
  • 17
  • 171
  • 225