10 September 2010

SetLocal EnableDelayedExpansion in CMD Scripts

In a Windows CMD for loop, variables within the loop aren't, by default, resolved into a value for every iteration of the loop. Here's a script that should list all files in a folder.

@echo off
for /f %%a in (*) do (
  set test=%%a
  echo %test%
)

However, when you run the script, only the first file found is output (the variable test is only set in the first iteration of the loop). Turns out that I'm the n'th generation of CMD programmers to trip over this issue. It seems that CMD only processes the for (...) statement once, so the variable test is only set once. To get CMD to reprocess your variable in each iteration, put your code into a setlocal EnableDelayedExpansion ... endlocal block and delimit with exclamation marks any variables that CMD should reprocess in each iteration of the loop (hence the unintuitive name of the block).

@echo off
setlocal EnableDelayedExpansion
for %%a in (*) do (
  set test=%%a
  echo test=!test!
)
endlocal

I couldn't find an official MS documentation of EnableDelayedExpansion or the use exclamation marks for variables.