Problems with for loops in batch file - loops

I am trying to create a for loop in batch with some calculation using modulus from 1-100 then return an average for the entire set of numbers. I want to print this average on the screen and to a file called output This is what i have but it doesn't seem to be working correctly. Any suggestions? Thank you kindly.
#echo off
setlocal EnabledDelayedExpansion
for /l %%i in (1,1,100) do (
set /a EXPR = %%i %% 5
set /a EXPR2 = %EXPR+3
set /a TOTAL = TOTAL+%EXPR2
)
set /a AVG = %TOTAL/100
echo Your average is %AVG
echo Your average is %AVG >> output.txt

#echo off
setlocal EnableDelayedExpansion
for /l %%i in (1,1,100) do (
set /a EXPR=%%i %% 5
set /a EXPR2=EXPR+3
set /a TOTAL=TOTAL+EXPR2
)
set /a AVG=TOTAL/100
echo Your average is %AVG%
echo Your average is %AVG%
Is this what you want?
One additional d in EnableDelayedExpansion (btw. set /a works also without delayed expansion). Classical error is to let spaces surrounding variable assignment.In batch scripts result is that the space becomes part of the variable name.Except FOR tokens and command line arguments variables are two side enclosed with %

Related

Setting random variable value in for loop in batch file gives errors

Here is my code:
for %%i in ("joined/*.mp4") do (
set /a result=(%random%*2/32768)+1
echo %result%
)
It gives me errors about +1 was unexpected at this time.
I tried another variant:
for %%i in ("joined/*.mp4") do (
set /a result=(%random%*2/32768)
echo %result%
)
It gives me an error about unbalanced parenthesis.
How can I echo the random variable correctly?
Thanks. :)
Trying the following code gives me the same value of random every time. How can I change it with each itertion of the loop?
setlocal EnableDelayedExpansion
for %%i in ("joined/*.mp4") do (
set /a result= %random%*20/32768 + 1
echo !result!
)
Is there a resource that I can read to learn in detail how batch files work and their language like loops, arrays etc.? I tried searching on Google but nothing useful came up.
Using brackets, (parentheses), is perfectly fine, and I would say more correct, so there's no reason why you cannot continue to do so.
Hare some options for you, which maintain their use:
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
For %%G In ("joined\*.mp4") Do (
Set /A result = (!random! * 20 / 32768^) + 1
Echo !result!
)
Pause
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
For %%G In ("joined\*.mp4") Do (
Set /A "result = (!random! * 20 / 32768) + 1"
Echo !result!
)
Pause
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
For %%G In ("joined\*.mp4") Do (
Set /A result = (!random! %% 20^) + 1
Echo !result!
)
Pause
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
For %%G In ("joined\*.mp4") Do (
Set /A "result = (!random! %% 20) + 1"
Echo !result!
)
Pause
As explained in the link provided by #Stephan, you'll need the ! on random too.
You can do it like this (for some reason, (!random!*20)/32768 triggers "/32768" was unexepected, so you have to split it on two lines :
setlocal EnableDelayedExpansion
for %%i in ("joined/*.mp4") do (
set /a result = !random!*20
set /a result= !result!/32768 +1
echo !result!
)

Command prompt script to subtract variables

I know there are many arithmetic questions on here, but I have not found the specific answer to my question. I have a file with two values in it, the first always higher than the second. Today, the txt file has:
21.04
20.94
What I am trying to do is, via a batch file, subtract the second number from the first, and then insert than on a new line. Any assistance is appreciated.
Just incorporate powershell into the batch file.
to test from cmd:
#for /f %i in ('powershell 21.04 - 20.94') do #echo %i
So you can build a very basic calculator rather easily.
set /p "first=Enter first number: "
set /p "second=Enter Second Number: "
set /p "function=Select Function(+-/): "
powershell %first% %function% %second%
And offcourse you can use a for loop to assign the value to a variable should you want to use it elsewhere in your batch file.
#echo off
set /p "first=Enter first number: "
set /p "second=Enter Second Number: "
set /p "function=Select Function(+-/): "
for /f %%i in ('powershell %first% %function% %second%') do set "result=%%i"
echo %result%
in a batch-file you double the % in meta variables to %%i
Assuming file is called math.txt
#echo off
setlocal enabledelayedexpansion
set cnt=1
for /f "usebackq" %%i in ("d:\math.txt") do (
set var!cnt!=%%i
set /a cnt+=1
)
(powershell %var1% - %var2%)>output.txt
pause
This method works with numbers up to 9 total digits (and any number of decimals) as long as the input numbers have the same number of decimals:
#echo off
setlocal EnableDelayedExpansion
rem Read two numbers
( set /P "num1=" & set /P "num2=" ) < test.txt
rem Adjust *two* numbers for given decimals
set "decimals=2"
for %%i in (1 2) do (
set "num%%i=!num%%i:.=!"
for /L %%d in (1,1,%decimals%) do if "!num%%i:~0,1!" equ "0" set "num%%i=!num%%i:~1!"
)
rem Subtract second number from the first
set /A "result=num1 - num2"
rem Adjust result for given number of decimals
for /L %%d in (1,1,%decimals%) do if "!result:~%decimals%!" equ "" set "result=0!result!"
rem Output result with decimals
echo !result:~0,-%decimals%!.!result:~-%decimals%!
I think this works for reasonably sized numbers:
#echo off
rem read values from file specified as command line parameter
(
set /p value1=
set /p value2=
)<%1
rem split first value into whole and fractional parts
for /f "tokens=1,2 delims=." %%a in ("%value1%") do (
set beforedot1=%%a
set afterdot1=%%b
)
rem reconstruct first value as fixed point number
set afterdot1=%afterdot1%00000
set afterdot1=%afterdot1:~0,6%
set value1=%beforedot1%%afterdot1%
rem split second value into whole and fractional parts
for /f "tokens=1,2 delims=." %%a in ("%value2%") do (
set beforedot2=%%a
set afterdot2=%%b
)
rem reconstruct second value as fixed point number
set afterdot2=%afterdot2%00000
set afterdot2=%afterdot2:~0,6%
set value2=%beforedot2%%afterdot2%
rem subtract values
set /a diff=value1-value2
rem convert fixed point value back
if "%diff:~0,-6%" == "" (
set diff=0.%diff:~-6%
) else (
set diff=%diff:~0,-6%.%diff:~-6%
)
rem remove trailing zeros
:loop
if "%diff:~-1%" == "0" (
set diff=%diff:~0,-1%
goto :loop
)
echo %diff%

How to find large factorials using a batch script

#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a temp=0
set /a digits=1
set /a array1=1
for /L %%i IN (2,1,%1) do (
set /a temp=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a temp=!temp!+!array%%j!*%%i
set /a array%%j=!temp!%%10
set /a temp=!temp!/10 )
set /a index=!digits!+1
for /L %%v IN (!index!,1,!index! ) do (
if !temp! NEQ 0 (
set /a array!index!=!temp!%%10
set /a temp/=10
set /a index+=1 ))
set /a digits=!index!-1)
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
:end
pause
This is what i have gotten so far. It is quite stable under 10! but once i reach 15 or 20 it starts missing out a few digits.
My edit....
#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a temp=0
set /a digits=1
set /a array1=1
for /L %%i IN (2,1,%1) do (
set /a temp=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a temp=!temp!+!array%%j!*%%i
set /a array%%j=!temp!%%10
set /a temp=!temp!/10 )
for /l %%v IN ( 1,1,30 ) do (
if !temp! neq 0 (
set /a digits+=1
set /a array!digits!=!temp!%%10
set /a temp=!temp!/10
)))
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
:end
pause
Now i am forcing the the last inner loop to run 30 times eventhough temp would have been zero way before that. Is there any way to write a snippet that would be analogous to the following c code
while (temp)
{/code goes here/}
This execute only as long as temp is non zero.
Is there any partyicular limit to how big a variable can be in a batch?
I know it is a pain * to debug computational programs in a batch, I'm just trying to code this in all programming languages i know, Just so i could compare their speeds. Can somebody Please point out what i'm doing wrong here.
edit........22/12/13
#echo off
if %1.==. ( echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end )
setlocal enabledelayedexpansion
set /a count=0
set /a tempo=0
set /a digits=1
set /a array1=1
for /f "tokens=1-4 delims=:.," %%a IN ("%time%") do (
set /a "start=(((%%a*60)+1%%b %% 100)*60+1%%c %%100)*100+1%%d %% 100"
)
for /L %%i IN (2,1,%1) do (
set /a tempo=0
for /L %%j IN ( 1,1,!digits! ) do (
set /a tempo=!tempo!+!array%%j!*%%i
set /a array%%j=!tempo!%%10000
set /a tempo=!tempo!/10000 )
for /l %%v IN (1,1,2) do (
if !tempo! neq 0 (
set /a digits+=1
set /a array!digits!=tempo%%10000
set /a tempo=tempo/10000
))
)
for /l %%v IN ( !digits!,-1,1 ) do set array=!array!!array%%v!
echo !array!
echo Total # of decimal digits = !digits!
for /f "tokens=1-4 delims=:.," %%a in ("%time%") do (
set /a "end=(((%%a*60)+1%%b %% 100)*60+1%%c %%100)*100+1%%d %% 100"
)
set /a elapsedcs=end-start
set /a elapseds=elapsedcs/100
set /a elapsedcs=elapsedcs%%100
echo %elapseds%.%elapsedcs% seconds
:end
rem label should never be the last statement
Is this what you meant aacini?
In order to achieve fast arithmetic operations on Big numbers in Batch, you must split the Bignum in groups of digits that can be managed via the 32-bits operations of set /A command. The maximum 32-bits signed integer is 2147483647, so the largest group of digits that can be multiplied this way is 4, because 5 digits (99999 x 99999) exceed the maximum number. Addition and multiplication must be achieved from right to left translating a "carry" to the next group to the left. Subtraction and division must be achieved from left to right translating a "borrow" to the next group to the right. The Batch file below use this method to succesively multiply a Bignum by a 4 digits factor, so it can calculate up to 9999! as long as all variables that contain the groups of 4 digits fits in the 64 MB size limit of the environment (look for "65,536KB maximum size" under "Setting environment variables"). The result is directly output to the screen in order to avoid the 8192 digits limit of one Batch variable.
EDIT: I slightly modified the program in order to run faster and get the number of digits in the result.
#echo off
if "%1" equ "" (
echo Missing parameter! Try passing the number as a parameter like 'factorial 10' without the quotes.
goto end
)
setlocal EnableDelayedExpansion
rem Calculate the factorial
set /A g1=1, groups=1
for /L %%n in (2,1,%1) do (
set carry=0
for /L %%g in (1,1,!groups!) do (
set /A group=g%%g*%%n+carry, g%%g=group%%10000, carry=group/10000
)
if !carry! neq 0 (
set /A groups+=1
set g!groups!=!carry!
)
)
rem Show the factorial
set /P "=!g%groups%!" < NUL
set /A groupsM1=groups-1
for /L %%g in (%groupsM1%,-1,1) do (
set group=000!g%%g!
set /P "=!group:~-4!" < NUL
)
echo/
rem Get the number of digits
set digits=0
for /L %%i in (0,1,3) do if "!g%groups%:~%%i,1!" neq "" set /A digits+=1
set /A digits+=4*groupsM1
echo Total # of decimal digits = %digits%
:end
pause
I had to rereread the code to see what it is doing. Nice.
You have to face three limits on your code.
1 - In the inner %%j and %%v loop, where buffer is used to multiply the current value in %%i, you face the limit indicated by Magoo. You can not operate with set /a with values greater than 2^31. As the values in the array are limited to 0-9, this means that this limit will not let you calculate factorials of numbers greater than 214748364 (aprox)
2 - There is a limit in the size of a environment variable. It can not hold more than 32767 characters. As you are concatenating the digits to output to console (the next limit is related), this limits you to factorials of numbers below 9273 (aprox).
3 - There is a limit in the length of the lines cmd can handle. It is 8191 characters. This does not limit your calc, but you can not use the method of concatenating in a variable to represent the number. If the method is not changed, this limits you to factorials of numbers below 2727 (aprox).
Batch is limited to signed-32-bit integers.
BTW - don't use temp or tmp as a user-variable. It is set by the system as a pointer to a directory where temporary files are stored.

Add random number to batch file that generates temp passwords

I would be very grateful if some one could help me fix my script, I want to add a 4 digit random number to the end of a string, in essence it is a script that reads a csv file for an email address then creates a powershell file for me to run but the part im having issues with is the random 4 digit number appended to the password string, please see below, if I run the script now it runs without errors but no 4 digit random number appended, can anyone help im sure its something small im missing thanks
Spud
#echo off & setlocal EnableDelayedExpansion
for /F "delims=" %%j in ('type "Input.csv"') do (
set /A RND=%RANDOM% %% 8889 + 1111
echo.Set-MsolUser -UserPrincipalName %%j -StrongPasswordRequired $false
echo.Set-MsolUserPassword -userPrincipalName %%j -NewPassword "TTech%RND%*" -ForceChangePassword $false
echo.Set-MsolUser -UserPrincipalName %%j -PasswordNeverExpires $true
echo.
) >> "Output.txt"
You need to change %var% to !var! to access the dynamic value of a variable with delayedexpansion in effect.
set /A RND=!RANDOM! %% 8889 + 1111
would set your variable RND to 1111..9999
echo.Set-MsolUserPassword -userPrincipalName %%j -NewPassword "TTech!RND!*" -ForceChangePassword $false
would then append the resultant value to TTech
Alternatively, try
set RND=000!RANDOM!
...
echo.Set-MsolUserPassword -userPrincipalName %%j -NewPassword "TTech!RND:~-4!*" -ForceChangePassword $false
which would construct a string 000+0..32767 and then use the last 4 characters after TTech so you'd get leading-zero-filled 4-digit numerics.
Use this for your random number:
Set max=9999
Set min=1000
Set /A rand=%random% %% (max - min + 1)+ min
Echo %rand%
Keep in mind, inside of a for loop, you'll need to use delayedexpansion and escape the parenthesis.
Set max=9999
Set min=1000
for /l %%a in (1,1,10) do (
Set /A rand=!random! %% ^( max - min + 1 ^) + min
Echo.!rand!
)
exit /b
Based on Magoo's answer, you know the issue was with using delayed variable syntax instead of standard parens. I wrapped up his answer and mine into a couple of little functions that are easily reusable.
call :RandomRange 1000 9999 ret
Echo %ret%
call :RandomRange2 ret
echo %ret%
exit /b
:RandomRange min max ret
#echo off & setlocal enabledelayedexpansion
Set /A rand=!random! %% (%2 - %1 + 1) + %1
endlocal & set %3=%rand%
exit /b
:RandomRange2 ret
#echo off & setlocal enabledelayedexpansion
set rnd=000!random!
set rnd=!rnd:~-4!
endlocal & set %1=%rnd%
exit /b
Hope that helps
This will give you a random 4 digit number:
set num=%random%%random%%random%%random%
set num=%num:~-4%
Or with delayed expansion enabled inside a loop:
set num=!random!!random!!random!!random!
set num=!num:~-4!

add multiple numbers in batch

i try to add two numbers received from a file.
But it shows only the last value of sum. Thx for the help!
#FOR /F "eol=; tokens=1-3 delims=, " %%i IN (test.txt) DO (
set m=%%j
set n=%%k
set /a sum=%m%+%n%
echo sum = %sum%
)
and in the test.txt i have
alex 4 5
john 6 7
and i want to see
sum=9
sum=13
it only shows
sum=13
sum=13
The problem is the percent expanding in the line set /a sum=%m%+%n% and echo sum = %sum%.
These are expanded before the FOR-loop is executed.
Therefore you got the result of the "global" set of sum.
It's better to use the delayed expansion, as then all variables enclosed with ! are expanded at runtime not parsetime
#echo off
setlocal EnableDelayedExpansion
FOR /F "eol=; tokens=1-3 delims=, " %%i IN (test.txt) DO (
set m=%%j
set n=%%k
set /a sum=m+n
echo sum = !sum!
)

Resources