Arithmetic inside a for loop batch file - batch-file

I have a for loop in a batch file that looks like this:
for %%y in (100 200 300 400 500) do (
set /a x = y/25
echo %x%
)
The line:
set /a x = y/25
Doesn't seem to be doing any division. What is the correct syntax for dividing each y by 25? I only need the integer result from this division.

Environment variables need not be expanded to use in a SET /A statement. But FOR variables must be expanded.
Also, even if your computation worked, the ECHO would fail because percent expansion takes place when a statement is parsed, and the entire FOR construct is parsed at once. So the value of %x% would be the value as it existed before the loop is executed. To get the value that was set within the loop you should use delayed expansion.
Also, you should remove the space before the assignment operator. You are declaring a variable with a space in the name.
#echo off
setlocal enableDelayedExpansion
for %%A in (100 200 300 400 500) do (
set n=%%A
REM a FOR variable must be expanded
set /a x=%%A/25
REM an environment variable need not be expanded
set /a y=n/25
REM variables that were set within a block must be expanded using delayed expansion
echo x=!x!, y=!y!
REM another technique is to use CALL with doubled percents, but it is slower and less reliable
call echo x=%%x%%, y=%%y%%
)

It's not doing anything because "y" is just a letter. You need percent signs to reference the variable.
set /a x = %%y/25

I was having the same issue but turned out to be an integer issue. I was multiplying after dividing but need to before. What was happening is something like this:
1/100x100 which operates like 1\100=0 then 0x100=0
I changed it to
1x100/100 which operates like 1x100=100 then 100/100=1
#echo off
setlocal ENABLEDELAYEDEXPANSION
for /f "usebackq" %%b in (`type List.txt ^| find "" /v /c`) do (
set Count=%%b
)
)
REM Echo !Count! -->Returns the correct number of lines in the file
for /F "tokens=*" %%A in (List.txt) do (
set cName=%%A
set /a Number+=1
REM Echo !Number! -->Returns the correct increment of the loop
set /a Percentage=100*!Number!/!Count!
REM Echo !Percentage! -->Returns 1 when on the first line of a 100 line file
set a=1
set b=1000
set /a c=100*1/100
Rem -->echo c = !c! --Returns "C = 1"
)

Related

using incremented variable in echo statement batch file without modifying it again and again

I am using command prompt in windows 7 but my question should apply for any windows version xp and above.
I am using a variable but want to echo incremented value in an echo statement .
Currently , I increment then echo then decrement variable as shown below
set /a count=<some value>
set /a count+=1
echo %count%
set /a count-=1
Process count having <same value>
I hope there is a better way to increment the value of the variable by just using echo.
Thanks.
You want something effectively like echo %count%+1? No, this won't work. The only way to do math in cmd is the set /a command.
I personally won't touch my original variable but use a dummy var;
set /a xcount=count+1
echo %xcount%
(just a thing of personal preference).
What actually would work:
set /a count=5
cmd /c set /a x=count+1
cmd /c set /a x=count+1 & echo/ this is plus one
cmd /c "<nul set /p "x=%Count% plus one is " & set /a x=count+1 &echo/. Ready."
echo %count% is still 5
because the set command is then done (in a new process) directly "on the command line" and set /a shows the result when done on the command line (but doesn't show the result in a batch file).
Contra: It's quite easy to show just the number (first cmd... line), but if you want to put some text "around", it quickly gets ugly (second line to append text, third line to put text around the number). And you open a new process. If you do it in a loop (as the variable name count suggests), it may slow down your script considerably.
You could use delayed expansion, via SETLOCAL and ENDLOCAL, without creating an intermediate variable or running another instance of cmd.exe.
Rem Ensure extensions are enabled for SET /A functionality
Rem and disable delayed expansion.
SetLocal EnableExtensions DisableDelayedExpansion
Rem Define variable named count with the string value of an integer
Set "count=5"
Rem Print the value
Echo %count%
Rem Enable delayed expansion
SetLocal EnableDelayedExpansion
Rem increment the variable value
Set /A count += 1
Rem Print the new value
Echo !count!
Rem Discard variables defined or modified during previous SETLOCAL
EndLocal
Rem Print the value
Echo %count%
#Rem Optional PAUSE for GUI invoked script
#Pause
A for /f loop is another means that avoids delayed expansion or setlocal / endlocal which can be used to get offset values without modifying the original count:
#Echo off
For %%O in (+ -)Do for /f "Delims=" %%G in ('Set /A "count%%O=1"')Do Echo(%Count% %%O 1 = %%G

Batch file - loop through first n lines of text file

I'm trying to determine the format of a text file by looping through the first 10 lines, perform some regex matching and then compare the results at the end. I can easily loop through the entire file, but I only want the first N lines (in this case 10)
I'm familiar with other languages, but the idiosyncrasies of this batch file is throwing me for a loop so to say.
Here is what I have so far:
#echo off
setlocal enableDelayedExpansion
set /A REGEXCOUNTER=0
set /A COUNTER=0
for /F %A in (%submitfile%) do (
set /A COUNTER=COUNTER+1
rem echo %A
setlocal enableDelayedExpansion
echo(%A|findstr /r /c:"[0-9].*" >nul && (
set /A REGEXCOUNTER=REGEXCOUNTER+1
echo %COUNTER% - %REGEXCOUNTER% - FOUND - %A
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)
rem LOOP END
if %COUNTER% GEQ 10 do (goto loop_over)
)
)
:loop_over
echo "END HERE!"
I've got counters set up that incrementally tick up to count my matches and how many times it's looped. However here is some sample output of variable values:
110 - 0 - FOUND - 003
220 - 0 - FOUND - 2
330 - 0 - FOUND - 1
440 - 0 - FOUND - 029
The loop counter variable is increasing by ten for each loop and the regex match counter is not going up at all. I'm pretty sure this has something to do with variable scope but I'm not sure where to begin.
This should fix all the issues I talked about in my comments above.
#echo off
setlocal enableDelayedExpansion
set /A REGEXCOUNTER=0
set /A COUNTER=0
for /F %%A in (%submitfile%) do (
set /A COUNTER=COUNTER+1
rem echo %%A
echo(%%A|findstr /r /c:"[0-9].*" >nul && (
set /A REGEXCOUNTER=REGEXCOUNTER+1
echo !COUNTER! - !REGEXCOUNTER! - FOUND - %%A
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)
rem LOOP END
if !COUNTER! GEQ 10 goto loop_over
)
)
:loop_over
echo "END HERE"
The extra setlocal within the loop should be removed. Once setlocal enabledelayedexpansion has been executed, it remains in effect until a setlocal disabledelayedexpansion is executed or until the batch terminates.
Each %A (the loop-control metavariable must be %%A (one % if run from the command-line, two if within a batch file)
If you change the value of a variable within the loop, then you need to refer to the changed value as !varname!, not %varname% which is the original value (search SO for delayed expansion). set /a always works on the current variable value.

Line reading program does not work

I have a program that reads the file and outputs a random file line number, but when it goes to output it, it just says "Echo is off" Is it possible to fix this?
Here is my code:
#echo off
setlocal enabledelayedexpansion
set Counter=1
for /f "tokens=* delims=" %%x in (Lists.txt) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
)
set /a Counter=%random% * 100 / 32768 + 1
echo %Counter%
echo "%Line_!Counter!%"
::Just displays echo is off
pause
echo "!Line_%Counter%!" will work. (not very intuitive, but makes sense, if you think about it)
There are two problems in your code.
The first has been pointed by Stephan. If you read the answers to this question, you will see that the parser replaces variables referenced with percents before variables referenced with exclamation marks. So when the parsers tries to handle %Line_!Counter!%, !Counter! is still not replaced in the line so %Line_!Counter!% is an undefined variable and is replaced with nothing. The inverse (!Line_%Counter%!) works because when the parser reaches the line, the first substitution is the percent variable and the last the exclamation mark variable.
The second is a logic error. The line
set /a Counter=%random% * 100 / 32768 + 1
will not work as intended if the file has more or less than 100 lines. If it has more, the higher numbered lines will never be selected. If it has less lines, a high numbered non existing line can be selected and as it does no exist, you will again get an echo is off message trying to echo the variable.
#echo off
setlocal enabledelayedexpansion
set Counter=0
for /f "tokens=* delims=" %%x in (Lists.txt) do (
set /a Counter+=1
set "Line_!Counter!=%%x"
)
set /a "selected=%random% %% Counter + 1"
echo %selected%
echo "!Line_%selected%!"
pause

Windows Batch file processing - Loops

Am very new to batch scritping. I just tried to execute the below code for which am totally confused.
#echo off
set m=100
set i=0
FOR /L %%N IN (0,1,%m%)do (
set /a i=1+%i%
)
echo %i%
pause
Here, am incrementing i value until N reaches 100. So, am expecting the value of i at the end of loop to be 101 but it shows 1. Can anyone explain what's the reason behind this.
thanks
You need delayed expansion : http://www.robvanderwoude.com/variableexpansion.php
#echo off
setlocal enableDelayedExpansion
set m=100
set i=0
FOR /L %%N IN (;;0,1,%m%;;) do (
set /a i=1+!i!
)
endlocal & set /a i=%i%
echo %i%
In batch files, variable reads are replaced with their values at parse time, before executing the line or the block (code enclosed in parenthesis).
So, the %i% reference inside the for loop is replaced with the value of the variable before the for loop, that is, 0 , and %m% is replaced with 100, and what gets executed is
for /l %%n in (0 1 100) do ( set /a i=1+0 )
You can enable delayed expansion (setlocal enabledelayedexpansion command) and change the sintax from %i% to !i! to indicate the parser that reads to the variable should be delayed until the moment of executing the line. The code should be
#echo off
setlocal enabledelayedexpansion
set m=100
set i=0
FOR /L %%N IN (0,1,%m%)do (
set /a i=1+!i!
)
echo %i%
endlocal
The read of the value of i inside the for loop is delayed. This way, the real value is readed just before each execution of the line. Reference to i out of the loop does not need it. When the line is reached and parsed, the correct value is retrieved and echoed.
Anyway, while this is the general rule, set /a has a different behaviour. If you change your code to
set /a i+=1
or
set /a i=i+1
the parser will correctly identify the operation and execute the expected code with or without delayed expansion enabled.

Returning a list of variables from a variadic function in a batch file

I have a function that takes a variable number of arguments. Each argument is a reference that the function will modify directly. Here is how I call the function:
set "A=" && set "B=" && set "C="
call :variadic_func A B C
echo [%A%][%B%][%C%]
goto :eof
If I don't use setlocal to limit variable scope, the function works fine. The function creates references X, Y, and Z and assigns them 1, 2, and 3. When the function returns, the caller sees that its variables A, B, and C are 1, 2, and 3. Good. Pretend that this is a variadic function and it figures out how many arguments it has at runtime.
:variadic_func
set "x=%1" && set "y=%2" && set "z=%3"
set "%x%=1" && set "%y%=2" && set "%z%=3"
goto :eof
Output:
C:\scratch\variadic_batch>variadic.bat
[1][2][3]
But I want to limit the scope of my function's variables with setlocal. So that means any values I write to X, Y, and Z get thrown away at the endlocal. How do I get the values out of the function?
:variadic_func
setlocal
set "x=%1" && set "y=%2" && set "z=%3"
set "%x%=1" && set "%y%=2" && set "%z%=3"
endlocal && (
call set "%x%=%%%%x%%%%"
call set "%y%=%%%%y%%%%"
call set "%z%=%%%%z%%%%"
)
goto :eof
Unfortunately, the calling context receives the values %x%, %y%, and %z%. I thought the code above would be expanded like so: 1. Expand %x% first to get call set A=%%A%%. Then the call gets executed and it would evaluate A=%A%. But I just end up assigning the text %A% to the variable A instead of evaluating it.
C:\scratch\variadic_batch>variadic.bat
[%x%][%y%][%z%]
Why is it not working like I expect, and how do I fix it?
(I just thought of doing a setlocal EnableDelayedExpansion before the function call so maybe delayed expansion would still be available when I do the endlocal in the function, but even if that works it'd be nice if the function didn't rely on the caller to be in a delayed expansion block... and I don't even know whether delayed expansion blocks stack)
This is an interesting topic! If you know in advance how many variables the function will get, you can assemble the appropiate line at end to return the values to the caller's environment this way:
:variadic_func
setlocal EnableDelayedExpansion
set "x=%1" & set "y=%2" & set "z=%3"
set "%x%=1" & set "%y%=2" & set "%z%=3"
for /F "tokens=1-3" %%a in ("!%x%! !%y%! !%z%!") do (
endlocal
set "%x%=%%a" & set "%y%=%%b" & set "%z%=%%c"
)
exit /B
However, if the number of variables is unknow, previous method can not be used.
(I used exit /B to terminate subroutines and goto :EOF for the main file only)
Your example is imprecise anyway, because if you don't know how many variables comes, you can NOT use fixed names as "x", "y" or "z". The only way to manage this situation is storing the names in an array and then process the array elements.
This way, before the function ends we could assemble a list of "var=value" pairs that will be executed in a FOR after the endlocal, so the variables will be defined in the caller's environment:
#echo off
call :variadic_func One Two Three
echo THREE VARS: One=[%One%] Two=[%Two%] Three=[%Three%] Four=[%Four%] Five=[%Five%]
call :variadic_func One Two Three Four Five
echo FIVE VARS: One=[%One%] Two=[%Two%] Three=[%Three%] Four=[%Four%] Five=[%Five%]
goto :EOF
:variadic_func
setlocal EnableDelayedExpansion
rem Collect the list of variable names in "var" array:
set i=0
:nextVar
if "%1" equ "" goto endVars
set /A i+=1
set var[%i%]=%1
shift
goto nextVar
:endVars
rem Assign random numbers to the variables (for example):
for /L %%i in (1,1,%i%) do (
set !var[%%i]!=!random!
)
rem Assemble the list of "var=value" assignments that will be executed at end:
set assignments=
for /L %%i in (1,1,%i%) do (
for %%v in (!var[%%i]!) do (
set assignments=!assignments! "%%v=!%%v!"
)
)
rem Execute the list of variable assignments in the caller's environment:
endlocal & for %%a in (%assignments%) do set %%a
exit /B
Output:
THREE VARS: One=[29407] Two=[21271] Three=[5873] Four=[] Five=[]
FIVE VARS: One=[30415] Two=[2595] Three=[22479] Four=[13956] Five=[26412]
EDIT:
I borrowed the method from dbenham's solution to return any number of variables with no limitations, excepting those noted by him. This is the new version:
#echo off
call :variadic_func One Two Three
echo THREE VARS: One=[%One%] Two=[%Two%] Three=[%Three%] Four=[%Four%] Five=[%Five%]
call :variadic_func One Two Three Four Five
echo FIVE VARS: One=[%One%] Two=[%Two%] Three=[%Three%] Four=[%Four%] Five=[%Five%]
goto :EOF
:variadic_func
setlocal EnableDelayedExpansion
rem Assemble the list of variable names in "var" array:
set i=0
:nextVar
if "%1" equ "" goto endVars
set /A i+=1
set var[%i%]=%1
shift
goto nextVar
:endVars
rem Assign random numbers to the variables (for example):
for /L %%i in (1,1,%i%) do (
set !var[%%i]!=!random!
)
rem Complete "var[i]=name" array contents to "var[i]=name=value"
for /L %%i in (1,1,%i%) do (
for %%v in (!var[%%i]!) do (
set "var[%%i]=%%v=!%%v!"
)
)
rem Execute the list of variable assignments in the caller's environment:
for /F "tokens=1* delims==" %%a in ('set var[') do endlocal & set "%%b"
exit /B
Antonio
Very interesting question, and I'm surprised how easy it is to solve :-)
EDIT - My original answer didn't quite answer the question, as Aacini noted in his comment. At the bottom I have a version that does directly answer the question. I've also updated my original answer to include a few more limitations that I discovered
You can return any number of variables very easily if you stipulate that the names of all variables to be returned are prepended with a constant prefix. The return variable prefix can be passed in as one of your parameters.
The following line is all that is needed:
for /f "delims=" %%A in ('set prefix.') do endlocal & set "%%A"
The entire results of the set prefix command is buffered before any iterations take place. The first iteration executes the only ENDLOCAL that is required to get back to the environment state that existed prior to the CALL. The subsequent ENDLOCAL iterations do no harm because ENDLOCAL within a CALLed function only work on SETLOCALs that were issued within the CALL. Additional redundant ENDLOCAL are ignored.
There are some really nice features of this very simple solution:
There is theoretically no limit to the number of variables that are returned.
The returned values can contain almost any combination of characters.
The returned values can approach the theoretical maximum length of 8191 bytes long.
There are also a few limitations:
The returned value cannot contain line feeds
If the final character of a returned value is a carriage return, that final carriage return will be stripped.
Any returned value that contains ! will be corrupted if delayed expansion is enabled when the CALL is made.
I have not figured out an elegant method to set a returned variable to undefined.
Here is a simple example of a variadic function that returns a variable number of values
#echo off
setlocal
set varBeforeCall=ok
echo(
call :variadic callA 10 -34 26
set callA
set varBeforeCall
echo(
call :variadic callB 1 2 5 10 50 100
set callB
set varBeforeCall
exit /b
:variadic returnPrefix arg1 [arg2 ...]
#echo off
setlocal enableDelayedExpansion
set /a const=!random!%%100
:: Clear any existing returnPrefix variables
for /f "delims==" %%A in ('set %1. 2^>nul') do set "%%A="
:: Define the variables to be returned
set "%~1.cnt=0"
:argLoop
if "%~2" neq "" (
set /a "%~1.cnt+=1"
set /a "%~1.!%~1.cnt!=%2*const"
shift /2
goto :argLoop
)
:: Return the variables accross the ENDLOCAL barrier
for /f "delims=" %%A in ('set %1. 2^>nul') do endlocal & set "%%A"
exit /b
And here is a sample run result:
callA.1=40
callA.2=-136
callA.3=104
callA.cnt=3
varBeforeCall=ok
callB.1=24
callB.2=48
callB.3=120
callB.4=240
callB.5=1200
callB.6=2400
callB.cnt=6
varBeforeCall=ok
Here is a version that is safe to CALL when delayed expansion is enabled
With a bit of extra code, it is possible to remove the limitation regarding CALLing the function while delayed expansion is enabled and the return value contains !.
The returned values are manipulated as necessary to protect ! when delayed expansion is enabled. The code is optimized such that the relatively expensive minipulation (particularly the CALL) is only executed when delayed expansion was enabled and the value contains !.
The returned value still cannot contain line feeds. A new limitation is that all carriage returns will be stripped if the returned value contains ! and delayed expansion was enabled when the CALL was made.
Here is a demo.
#echo off
setlocal
set varBeforeCall=ok
echo(
echo Results when delayed expansion is Disabled
call :variadic callA 10 -34 26
set callA
set varBeforeCall
setlocal enableDelayedExpansion
echo(
echo Results when delayed expansion is Enabled
call :variadic callB 1 2 5 10 50 100
set callB
set varBeforeCall
exit /b
:variadic returnPrefix arg1 [arg2 ...]
#echo off
:: Determine if caller has delayed expansion enabled
setlocal
set "NotDelayed=!"
setlocal enableDelayedExpansion
set /a const=!random!%%100
:: Clear any existing returnPrefix variables
for /f "delims==" %%A in ('set %1. 2^>nul') do set "%%A="
:: Define the variables to be returned
set "%~1.cnt=0"
:argLoop
if "%~2" neq "" (
set /a "%~1.cnt+=1"
set /a "%~1.!%~1.cnt!=%2*const"
shift /2
goto :argLoop
)
set %~1.trouble1="!const!\^^&^!%%"\^^^^^&^^!%%
set %~1.trouble2="!const!\^^&%%"\^^^^^&%%
:: Prepare variables for return when caller has delayed expansion enabled
if not defined NotDelayed for /f "delims==" %%A in ('set %1. 2^>nul') do (
for /f delims^=^ eol^= %%V in ("!%%A!") do if "%%V" neq "!%%A!" (
set "%%A=!%%A:\=\s!"
set "%%A=!%%A:%%=\p!"
set "%%A=!%%A:"=\q!"
set "%%A=!%%A:^=\c!"
call set "%%A=%%%%A:^!=^^^!%%" ^^!
set "%%A=!%%A:^^=^!"
set "%%A=!%%A:\c=^^!"
set "%%A=!%%A:\q="!"
set "%%A=!%%A:\p=%%!"
set "%%A=!%%A:\s=\!"
)
)
:: Return the variables accross the ENDLOCAL barrier
for /f "delims=" %%A in ('set %1. 2^>nul') do endlocal & endlocal & set "%%A"
exit /b
And some sample results:
Results when delayed expansion is Disabled
Environment variable callA not defined
callA.1=780
callA.2=-2652
callA.3=2028
callA.cnt=3
callA.trouble1="78\^&!%"\^&!%
callA.trouble2="78\^&%"\^&%
varBeforeCall=ok
Results when delayed expansion is Enabled
Environment variable callB not defined
callB.1=48
callB.2=96
callB.3=240
callB.4=480
callB.5=2400
callB.6=4800
callB.cnt=6
callB.trouble1="48\^&!%"\^&!%
callB.trouble2="48\^&%"\^&%
varBeforeCall=ok
Note how the format of the returned trouble values is consistent whether or not delayed expansion was enabled when the CALL was made. The trouble1 value would have been corrupted when delayed expansion was enabled if it were not for the extra code because of the !.
EDIT: Here is a version that directly answers the question
The original question stipulated that the names of each returned variable are supposed to be provided in the parameter list. I modified my algorithm to prefix each variable name with a dot within the function. Then I slightly modified the final returning FOR statement to strip off the leading dot. There is a restriction that the names of the returned variables cannot begin with a dot.
This version includes the safe return technique that allows CALLs while delayed expansion is enabled.
#echo off
setlocal disableDelayedExpansion
echo(
set $A=before
set $varBeforeCall=ok
echo ($) Values before CALL:
set $
echo(
echo ($) Values after CALL when delayed expansion is Disabled:
call :variadic $A $B
set $
setlocal enableDelayedExpansion
echo(
set #A=before
set #varBeforeCall=ok
echo (#) Values before CALL:
set #
echo(
echo (#) Values after CALL when delayed expansion is Enabled:
call :variadic #A #B #C
set #
exit /b
:variadic arg1 [arg2 ...]
#echo off
:: Determine if caller has delayed expansion enabled
setlocal
set "NotDelayed=!"
setlocal enableDelayedExpansion
:: Clear any existing . variables
for /f "delims==" %%A in ('set . 2^>nul') do set "%%A="
:: Define the variables to be returned
:argLoop
if "%~1" neq "" (
set /a num=!random!%%10
set ^".%~1="!num!\^^&^!%%"\^^^^^&^^!%%"
shift /1
goto :argLoop
)
:: Prepare variables for return when caller has delayed expansion enabled
if not defined NotDelayed for /f "delims==" %%A in ('set . 2^>nul') do (
for /f delims^=^ eol^= %%V in ("!%%A!") do if "%%V" neq "!%%A!" (
set "%%A=!%%A:\=\s!"
set "%%A=!%%A:%%=\p!"
set "%%A=!%%A:"=\q!"
set "%%A=!%%A:^=\c!"
call set "%%A=%%%%A:^!=^^^!%%" ^^!
set "%%A=!%%A:^^=^!"
set "%%A=!%%A:\c=^^!"
set "%%A=!%%A:\q="!"
set "%%A=!%%A:\p=%%!"
set "%%A=!%%A:\s=\!"
)
)
:: Return the variables accross the ENDLOCAL barrier
for /f "tokens=* delims=." %%A in ('set . 2^>nul') do endlocal & endlocal & set "%%A"
exit /b
And sample results:
($) Values before CALL:
$A=before
$varBeforeCall=ok
($) Values after CALL when delayed expansion is Disabled:
$A="5\^&!%"\^&!%
$B="5\^&!%"\^&!%
$varBeforeCall=ok
(#) Values before CALL:
#A=before
#varBeforeCall=ok
(#) Values after CALL when delayed expansion is Enabled:
#A="7\^&!%"\^&!%
#B="2\^&!%"\^&!%
#C="0\^&!%"\^&!%
#varBeforeCall=ok
Remove a pair of the percents from the value. call set "%x%=%%%%x%%%%" into call set "%x%=%%%x%%%"
Currently it is evaluating as follows:
:: Here is the base command
call set "%x%=%%%%x%%%%"
:: The single percents are evaluated and the doubles are escaped.
set "A=%%x%%"
:: The doubles are escaped again leaving literal % signs
"A=%x%"
You want as follows:
:: Here is the base command
call set "%x%=%%%x%%%"
:: The single percents are evaluated and the doubles are escaped.
set "A=%A%"
:: The single percents are evaluated.
"A=1"
When doing variable expansion using the call command, single percents % get evaluate first, then double percents %% seconds due to batch escaping.
Batch commands are read from left to right. So when there are an even number of % signs such as %%%%, the first and third percent signs will be utilized as escape characters for the second and fourth leaving no percent signs left to be used for variable evaluation.

Resources