Variable Expansion in FOR Loops

One question about FOR loops has cost batch scripters many a sleepless night:

Why doesn't the SET command work in my FOR loop?

My counter-question is: Doesn't it?
I think it does exactly what you tell it to do.

On this page I'll try to explain how a FOR loop is interpreted, why it seems unable to SET variables, and how to SET variables in FOR loops anyway.
Once you understand how the FOR loop is interpreted, you'll know how to circumvent its limitations.

First some hands-on training: excercise 1

OK, what did we just find out?

It seems we can not change a variable within a FOR loop and use that changed variable in the same loop.

Can't we? Yes we can!

What we need is delayed variable expansion.
That means the variables are "expanded" not before but during command execution.

Typing SET /? and SETLOCAL /? on a DOS-prompt will show you more details on delayed variable expansion, as do the SET and SETLOCAL sections of AllHelp generated HTML pages.

Time for some hands-on training again: excercise 2

OK, what did we just learn?

  1. To use delayed variable expansion we need to enable it first.
    This can be done using CMD /V:ON /C to start the batch file, or, better yet SETLOCAL ENABLEDELAYEDEXPANSION inside the batch file.
  2. The variable whose expansion should be delayed should be surrounded by exclamation marks instead of percent signs.

A final note on FOR command layout:

FOR %%A IN (1 2 3) DO (
	SET VAR1=%VAR1%%%A
	SET VAR2=%VAR2%%%A
)

is identical to:

FOR %%A IN (1 2 3) DO (SET VAR1=%VAR1%%%A&SET VAR2=%VAR2%%%A)

Both are interpreted as a single FOR command line, so variable expansion takes place before execution of the FOR command.

So neither of these will work, unless used with delayed variable expansion:

FOR %%A IN (1 2 3) DO (
	SET VAR1=!VAR1!%%A
	SET VAR2=!VAR2!%%A
)

or:

FOR %%A IN (1 2 3) DO (SET VAR1=!VAR1!%%A&SET VAR2=!VAR2!%%A)

 

Note: Read about this bug in delayed variable expansion, found by Scott Wegner!

 

 


page last uploaded: 4 March 2011, 12:54
Fileaze