tags:

views:

104

answers:

1

File test.cmd:

name=dummy  

for /f "eol=; tokens=1 delims=," %%i in (list.txt) do (  
echo i: %%i  
set name=%%i  
echo name: %name%)  

the file list.txt contains this lines (one name per line):

John  
Tom  
Erica  
Sara  

Each time I launch this batch I get this output:

i: John  
name: dummy  
i:T om  
name: dummy  
i: Erica  
name: dummy  
i: Sara  
name: dummy  

It seems that the variable name does not get assigned the value of %%i

Any idea?

A: 

You're falling into the old trap of not using delayed expansion.

For a quick fix, just put

setlocal enabledelayedexpansion

before that loop in your batch file and use !name! instead of %name%.

CMD expands variables while parsing a command. A command in this sense is a single line or a “block”, delimited with parentheses. The complete for loop is only parsed once and in that stage %name% gets replaced with the value it has at that point, namely "dummy". Delayed expansion on the other hand uses ! instead of % to delimit variable names and the variables then get expanded right before execution of a command.

Whenever you are setting a variable inside a parenthesized block and use its value in the same block again you need to use delayed expansion. help set has also some info about this:

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "%VAR%" == "after" @echo If you see this, it worked
)

would never display the message, since the %VAR% in both IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing “before” with “after” which will never be equal. Similarly, the following example will not work as expected:

set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%

in that it will not build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%
Joey
Thank you very much! You definitaly saverd my day.fabio vitale
Fabio Vitale