Batch Counter not working - batch-file

I've got this code on a batch file:
setlocal EnableDelayedExpansion
set var=0
for /f "tokens=*" %%a in (kim.txt) do (
set /a var+=1
echo Line %var%
)
But %var% don't seem to increment, it's always at zero. Tried different aproaches without any luck.

Under delayed expansion you need to access your variables (in case their value changes within brackets context) with ! instead of % :
setlocal EnableDelayedExpansion
set var=0
for /f "tokens=*" %%a in (kim.txt) do (
set /a var+=1
echo Line !var!
)

Related

windows batch escape whole string

Ok. this is a self updating batch file. I just simplified the problem from a bigger file.
this is a windows batch file(.bat) that upon execution should open itself and update first line
SET variableName=D:\Data
setlocal enableextensions enabledelayedexpansion
set /A i=0
for /f "tokens=*" %%f in ('type "%0"^&cd.^>"%0"') do (
set /A i=!i!+1
if !i! EQU 1 (
echo SET variableName=D:\Data2>>%0
) else (
echo %%f>>%0
)
)
endlocal
so let explain the situation.
i have !i! variable in lines 5 and 6. after executing this file, the variable in each line will replace by line number. it obviously because of echo %%f>>%0 that could not ignore and escape variable.
and my question is how to solve this problem?
another less problem is that the above code ignores spaces at beginning of line (indents) and generates a flat file.
the result of executing this file is:
SET variableName=D:\Data2
setlocal enableextensions enabledelayedexpansion
set /A i=0
for /f "tokens=*" %%f in ('type "%0"^&cd.^>"%0"') do (
set /A i=5+1
if 6 EQU 1 (
echo SET variableName=D:\Data2>>%0
) else (
echo %%f>>%0
)
)
endlocal
Stopping expansion of the variable when executing the file is as simple as turning delayed expansion off prior to the line that updates the file, and pairing it with an endlocal.
Retaining the space / tab formatting is achieved by including delims= in the For loop options.
Set variableName=D:\Data
Setlocal enableextensions enabledelayedexpansion
Set /A i=0
For /f "tokens=* delims=" %%f in ('type "%0"^&cd.^>"%0"') do (
Set /A i+=1
If !i! EQU 1 (
Echo SET variableName=D:\Data2>>%0
) Else (
Setlocal DisableDelayedExpansion
Echo(%%f>>%0
Endlocal
)
)
Endlocal
set "variableName=D:\Data"
setlocal enableextensions enabledelayedexpansion
rem !test! exclaimations, %test% percentages
for /f "skip=1 delims=" %%A in ('
type "%~f0" ^&
^> "%~f0" echo set "variableName=D:\Data2"
') do (
setlocal disabledelayedexpansion
>> "%~f0" echo %%A
endlocal
)
endlocal
You can avoid counting as skip=1 can be used to skip the first line. Use delims= to avoid delimiting the line. tokens=* ignores delimiters at start of the line and get the remainder of the line so that can be omitted for this task.
The new first line is now in the for loop command instead of erasing the file to empty. If you echo more lines, then increase the skip number.
Also may need to use setlocal disabledelayedexpansion so exclamation marks are retained.
Modifying the same file that is being read can a risk, though I assume you understand the risk.

I not getting the correct value of my variable in command prompt using for loop

I have this batch file
SETLOCAL ENABLEDELAYEDEXPANSION
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`find "# STATISTICS ON CLIENT_JE_AMT EY_ENT_DATE EY_EFF_DATE" "z_B10_VALIDATION.LOG"`) DO (
SET var!count!=%%F
SET /a count=!count!+1
)
ECHO %var1%
ECHO %var2%
for /f "tokens=1 delims=:" %%i in ("%var2%") do (
set stat_line_start=%%i
)
echo %stat_line_start%
set /a stat_line_end=!stat_line_start!+3
for /L %%j in (%stat_line_start%,1,%stat_line_end%) do (
echo %%j
set k=%%j
set cfirst=%k:~0,1%
set csec=%k:~1,1%
set cthird=%k:~2,1%
findstr /B "[%cfirst%-%cfirst%][%csec%-%csec%][%cthird%-%cthird%]:" "z_B10_VALIDATION.LOG">> z_STATS.txt
)
ENDLOCAL
when i run this, I am getting the correct value for variable "k" but having error on "cfirst", "csec" and "cthird" variable.
sample result line :
set k=254
set cfirst=~0,1
instead of
set cfirst=2
I am new on this field and just starting to explore. Hope you can help me.
Thank you in advance.
CMD expands variables when the command is parsed, not when it is run.
Because code blocks (i.e. chunks of code suurrounded by parentheses - like multi-line if statements and for loops) are considered a single command by the interepreter, any variables that you set inside of the block are set to the default value: nothing.
You can delay this expansion to runtime with the command setlocal enabledelayedexpansion (which you already included at the top of your code) and using the !variable! syntax instead of the %variable% syntax.

BATCH, summarize variables inside FOR loop

I have a batch file with a FOR loop inside like this:
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G)
It works like a charm %%G will 1,2,3,4,5.
Now I want a new wariable like test=%%G+1 and it will be: 2,3,4,5,6
But with this code it didn't works.
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G
set /a test=%%G+1
echo %test%
)
test variable will be every time: 6
What should I do?
Thanks
Roberto
You need to use EnabledDelayedExpansion when evaluating variables which are set inside a FOR loop:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
set /a target=5
FOR /L %%G IN (1,1,%target%) DO (
echo %%G
set /a test=%%G+1
REM Note the exclamation marks.
REM This is delayed expansion notation.
echo !test!
)
ENDLOCAL
If you do not use delayed expansion, then all variables are evaluated on the first pass of the FOR loop, so %test% will not actually have a value at this time.
By turning on delayed expansion (and using the !test! notation), the script will evaluate the value of !test! on each pass.

How to set a variable inside a loop for /F

I made this code
dir /B /S %RepToRead% > %FileName%
for /F "tokens=*" %%a in ('type %FileName%') do (
set z=%%a
echo %z%
echo %%a
)
echo %%a is working fine but echo %z% returns "echo disabled".
I need to set a %z% because I want to split the variable like %z:~7%
Any ideas?
There are two methods to setting and using variables within for loops and parentheses scope.
setlocal enabledelayedexpansion see setlocal /? 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.
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.
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
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
To expand on the answer I came here to get a better understanding so I wrote this that can explain it and helped me too.
It has the setlocal DisableDelayedExpansion in there so you can locally set this as you wish between the setlocal EnableDelayedExpansion and it.
#echo off
title %~nx0
for /f "tokens=*" %%A in ("Some Thing") do (
setlocal EnableDelayedExpansion
set z=%%A
echo !z! Echoing the assigned variable in setlocal scope.
echo %%A Echoing the variable in local scope.
setlocal DisableDelayedExpansion
echo !z! &rem !z! Neither of these now work, which makes sense.
echo %z% &rem ECHO is off. Neither of these now work, which makes sense.
echo %%A Echoing the variable in its local scope, will always work.
)
set list = a1-2019 a3-2018 a4-2017
setlocal enabledelayedexpansion
set backup=
set bb1=
for /d %%d in (%list%) do (
set td=%%d
set x=!td!
set y=!td!
set y=!y:~-4!
if !y! gtr !bb1! (
set bb1=!y!
set backup=!x!
)
)
rem: backup will be 2019
echo %backup%
Try this:
setlocal EnableDelayedExpansion
...
for /F "tokens=*" %%a in ('type %FileName%') do (
set z=%%a
echo !z!
echo %%a
)
You can use a macro if you access a variable outside the scope
#echo off
::Define macro
set "sset=set"
for /l %%a in (1,1,4) do (
::set in loop
%sset% /a "x[%%a]=%%a*%%a"
if %%a equ 4 (
:: set in condition
%sset% "x[%%a]=x Condition"
%sset% "y=y Condition"
)
)
echo x1=%x[1]% x2=%x[2]% x3=%x[3]% x4=%x[4]% y=%y%
:: Bonus. enableDelayedExpansion used to access massive from the loop
setlocal enableDelayedExpansion
echo Echo from the loop
for /l %%a in (1,1,4) do (
::echo in one line - echo|set /p =
echo|set /p "=x%%a=!x[%%a]! "
if %%a equ 4 echo y=%y%
)
pause
I know this isn't what's asked but I benefited from this method, when trying to set a variable within a "loop". Uses an array. Alternative implementation option.
SETLOCAL ENABLEDELAYEDEXPANSION
...
set Services[0]=SERVICE1
set Services[1]=SERVICE2
set Services[2]=SERVICE3
set "i=0"
:ServicesLoop
if defined Services[%i%] (
set SERVICE=!Services[%i%]!
echo CurrentService: !SERVICE!
set /a "i+=1"
GOTO :ServicesLoop
)
The following should work:
setlocal EnableDelayedExpansion
for /F "tokens=*" %%a in ('type %FileName%') do (
set "z=%%a"
echo %z%
echo %%a
)

skip=!count! is not working in windows(7) batch file

In for loop i have checked condition, if condition is true i have set the count value and skipped some lines in file,
#echo off
SetLocal EnableDelayedExpansion
set /a count=0
set for_parameters="skip=!count! delims="
for /f %for_parameters% %%a in ('list.txt') do (
echo %%a
if %%a==Exception: (
set /a count+=2
)
)
Endlocal
Its shows delims=" was unexpected at this time. Error
Can anyone help me to fix this problem .....
What jeb said about delayed expansion and FOR options is true - you can't use it - but that has nothing to do with the problem in your code.
You are using delayed expansion before you use the expression in your FOR statement, so there is no problem there.
Your problem is that you are attempting to set SKIP=0. The SKIP value must be >0 to be valid. The fix is simple: don't include the SKIP option if you don't want to skip any lines :-)
#echo off
SetLocal EnableDelayedExpansion
set /a count=0
set "skip="
if !count! gtr 0 set "skip=skip=!count!"
set for_parameters="!skip! delims="
for /f %for_parameters% %%a in ('list.txt') do (
echo %%a
if %%a==Exception: (
set /a count+=2
)
)
Endlocal
Expanding on jeb's point: you cannot do the following
for /f !for_parameters! %%a in ...
because FOR has special parsing rules. Most commands parse their options after delayed expansion. But FOR and IF parse their options before FOR variable expansion and delayed expansion take place. Neither FOR variables nor delayed expansion can be used to specify FOR or IF options.
In the for-options you can only use percent expansion, but not delayed expansion.
If your skip value itself is calculated in a block, then you need to extract the for loop into a function
You can use the More command to skip lines.
#echo off
:: By Elektro H#cker
SetLocal EnableDelayedExpansion
set /a count=2
for /F %%a in ('Type "list.txt" ^| MORE +!COUNT!') do (echo %%a)
Pause&exit

Resources