/flags/cmd/setlocal-enabledelayedexpansion
setlocal enabledelayedexpansion: why variables do not change inside a for loop
- tool
- Command Prompt (cmd)
- command
- setlocal
- flag
- enabledelayedexpansion
- default
- disabled (unless cmd /v:on or the DelayedExpansion registry value enables it)
cmd replaces %VAR% with its value when it reads a line, and a for loop or if (...) block is read as one line. A variable changed inside the block therefore still shows its old value there. setlocal enabledelayedexpansion turns on a second syntax, !VAR!, that is expanded each time the command runs. Use !VAR! for variables you change inside a block.
The difference
set count=0
for %%i in (a b c) do (
set /a count+=1
echo percent: %count%
)
echo after the loop: %count%
setlocal enabledelayedexpansion
set count=0
for %%i in (a b c) do (
set /a count+=1
echo delayed: !count!
)
endlocalOutput
percent: 0 percent: 0 percent: 0 after the loop: 3 delayed: 1 delayed: 2 delayed: 3
The variable does change inside the first loop; %count% was replaced by 0 before the loop started.
How setlocal works
setlocalstarts a local environment: everysetafter it is undone atendlocalor when the batch file ends.setlocal enabledelayedexpansiondoes the same and enables!VAR!untilendlocal.setlocal disabledelayedexpansionturns it off again.cmd /v:onenables delayed expansion for a whole cmd session, which is how it works at the interactive prompt.
To keep a value after endlocal, use the fact that %VAR% on the same line is expanded before endlocal runs:
setlocal enabledelayedexpansion
set "result=computed inside"
endlocal & set "result=%result%"
echo %result%Output
computed inside
Exclamation marks in data
With delayed expansion on, ! is special everywhere in the line, so text and file names that contain ! lose it:
setlocal enabledelayedexpansion
echo Hello world!
setlocal disabledelayedexpansion
echo Hello world!Output
Hello world Hello world!
Enable it only around the code that needs it, or turn it off while you process file names that may contain !.