You are not the first, who fell into the famous "delayed expansion trap" (and you won't be the last).
You need delayed expansion if you want to use a variable, that you changed in the same block (a block is a series of commands within brackets (
and )
).
Delayed variables are referenced with !var!
instead of %var%
.
Reason is the way, cmd
parses the code. A complete line or block is parsed at once, replacing normal variables with their value at parse time. Delayed variables are evaluated at runtime.
Two simple batch files to demonstrate:
setlocal EnableDelayedExpansion
set "var=hello"
if 1==1 (
set "var=world"
echo %var% !var!
)
setlocal EnableDelayedExpansion
for /L %%i in (1,1,5) do (
echo %random% !random!
)
Note: A line is also treated as a block:
set "var=old"
set "var=new" & echo %var%
With delayed expansion:
setlocal EnableDelayedExpansion
set "var=old"
set "var=new" & echo !var!
Delayed expansion is per default turned off at the command prompt. If you really need it, you can do:
cmd /V:ON /C "set "var=hello" & echo !var!"
Also there is a way to do the same without delayed expansion (but call
costs some time, so it's slower, but if for some reason you can't / don't want to use delayed expansion, it's an alternative):
setlocal DISabledelayedexpansion
for /L %%i in (1 1 5) do (
call echo %random% %%random%%
)
Both methods can also be used to display array-like variables:
(This is often asked like "variable which contains another variable" or "nested variables")
Here is a collection for using such array-like variables in different situations:
With delayed expansion:
setlocal ENableDelayedExpansion
set "num=4"
set "var[%num%]=HELLO"
echo plain delayed: !var[%num%]!
for /L %%i in (4 1 4) do (
echo for delayed: !var[%%i]!
set a=%%i
call echo for delayed with variable: %%var[!a!]%%
)
without delayed expansion:
setlocal DISableDelayedExpansion
set "num=4"
set "var[%num%]=HELLO"
call echo plain called: %%var[%num%]%%
for /L %%i in (4 1 4) do (
call echo FOR called: %%var[%%i]%%
set a=%%i
call echo FOR called with variable: %%var[%a%]%%
)
Note: setlocal
has no effect outside of batchfiles, so delayedexpansion
works only:
- In batch files
- When the cmd was started with delayed expansion enabled (
cmd /V:ON
) (by default, the cmd runs with delayed expansion disabled)
(Follow the links, when you are interested in the technical background or even the advanced technical stuff)