How to set a variable inside a loop for /F
Solution 1:
There are two methods to setting and using variables within for loops and parentheses scope.
setlocal enabledelayedexpansion
seesetlocal /?
for help. This only works on XP/2000 or newer versions of Windows. then use!variable!
instead of%variable%
inside the loop...-
Create a batch function using batch goto labels
:Label
.Example:
for /F "tokens=*" %%a in ('type %FileName%') do call :Foo %%a goto End :Foo set z=%1 echo %z% echo %1 goto :eof :End
Batch functions are very useful mechanism.
Solution 2:
You probably want SETLOCAL ENABLEDELAYEDEXPANSION
. See https://devblogs.microsoft.com/oldnewthing/20060823-00/?p=29993 for details.
Basically: Normal %variables%
are expanded right aftercmd.exe
reads the command. In your case the "command" is the whole
for /F "tokens=*" %%a in ('type %FileName%') do (
set z=%%a
echo %z%
echo %%a
)
loop. At that point z
has no value yet, so echo %z%
turns into echo
. Then the loop is executed and z
is set, but its value isn't used anymore.
SETLOCAL ENABLEDELAYEDEXPANSION
enables an additional syntax, !variable!
. This also expands variables but it only does so right before each (sub-)command is executed.
SETLOCAL ENABLEDELAYEDEXPANSION
for /F "tokens=*" %%a in ('type %FileName%') do (
set z=%%a
echo !z!
echo %%a
)
This gives you the current value of z
each time the echo
runs.
Solution 3:
I struggeld for many hours on this. This is my loop to register command line vars. Example : Register.bat /param1:value1 /param2:value2
What is does, is loop all the commandline params, and that set the variable with the proper name to the value.
After that, you can just use set value=!param1! set value2=!param2!
regardless the sequence the params are given. (so called named parameters). Note the !<>!, instead of the %<>%.
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%P IN (%*) DO (
call :processParam %%P
)
goto:End
:processParam [%1 - param]
@echo "processparam : %1"
FOR /F "tokens=1,2 delims=:" %%G IN ("%1") DO (
@echo a,b %%G %%H
set nameWithSlash=%%G
set name=!nameWithSlash:~1!
@echo n=!name!
set value=%%H
set !name!=!value!
)
goto :eof
:End
Solution 4:
Simple example of batch code using %var%, !var!, and %%.
In this example code, focus here is that we want to capture a start time using the built in variable TIME (using time because it always changes automatically):
Code:
@echo off
setlocal enabledelayedexpansion
SET "SERVICES_LIST=MMS ARSM MMS2"
SET START=%TIME%
SET "LAST_SERVICE="
for %%A in (%SERVICES_LIST%) do (
SET START=!TIME!
CALL :SOME_FUNCTION %%A
SET "LAST_SERVICE=%%A"
ping -n 5 127.0.0.1 > NUL
SET OTHER=!START!
if !OTHER! EQU !START! (
echo !OTHER! is equal to !START! as expected
) ELSE (
echo NOTHING
)
)
ECHO Last service run was %LAST_SERVICE%
:: Function declared like this
:SOME_FUNCTION
echo Running: %1
EXIT /B 0
Comments on code:
- Use enabledelayedexpansion
- The first three SET lines are typical uses of the SET command, use this most of the time.
- The next line is a for loop, must use %%A for iteration, then %%B if a loop inside it etc.. You can not use long variable names.
- To access a changed variable such as the time variable, you must use !! or set with !! (have enableddelayexpansion enabled).
- When looping in for loop each iteration is accessed as the %%A variable.
- The code in the for loop is point out the various ways to set a variable. Looking at 'SET OTHER=!START!', if you were to change to SET OTHER=%START% you will see why !! is needed. (hint: you will see NOTHING) output.
- In short !! is more likely needed inside of loops, %var% in general, %% always a for loop.
Further reading
Use the following links to determine why in more detail:
- Difference between %variable% and !variable! in batch file
- Variable usage in batch file