Reputation: 2287
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?
Upvotes: 1
Views: 2343
Reputation: 354406
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 bothIF
statements is substituted when the firstIF
statement is read, since it logically includes the body of theIF
, which is a compound statement. So theIF
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 theFOR
statement is read, and at that time theLIST
variable is empty. So the actualFOR
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%
Upvotes: 2