Batch script - Adding variable value to same variable - batch-file

I'm trying to do something like this, but I can't make it to work.
for /F "tokens=1" %%a in (C:\Auxiliar4.txt) do (
if !counter! EQU 3 (set /A failed=%%a)
if !counter! EQU 9 (set /A completed=%%a)
if !counter! EQU 6 (set /A total=%%a)
set /A counter+=1
)
set /A counter=0
set /A failedday=%failedday%+%failed%
if %total% NEQ 0 (set /A success=(%completed%*100)/%total%)
My problem is with these two lines:
set /A failedday=%failedday%+%failed%
if %total% NEQ 0 (set /A success=(%completed%*100)/%total%)
The first issue is with variable "failedday", I need to read numeric values from a txt file, assign them to those variables (failed, completed, total) and then assign the value of "failed" to "failedday". Then another FOR loop starts to read a different txt with same format, assign those numeric values to "failed", "completed", "total" again (losing the previous values), and add new value of "failed" to "failedday" keeping the previous addition (example, filedday=2 after first "for", after second should be failedday=2 + New"Failed"Value).
The second issue is with "IF" structure. I need to calculate the average of completed transactions taking values from "For" loop, only if "total" is not equal to 0 (to avoid divide by zero), but when I add this line my script crashes.
Could anyone help me with this? Thanks!!!

Here's a previous StackOverflow question that asks the same sort of thing.
Here's another reference for doing arithmetic with DOS Batch files.
You need to enable delayed expansion to perform the arithmetic:
#echo off & setlocal EnableDelayedExpansion
set /A failed=0
set /A completed=0
set /A total=0
for /F "tokens=1" %%a in (C:\Temp\test.txt) do (
if !counter! EQU 3 (set /A failed=%%a)
if !counter! EQU 9 (set /A completed=%%a)
if !counter! EQU 6 (set /A total=%%a)
set /A counter+=1
)
echo Failed: %failed%
echo Completed: %completed%
echo Total: %total%
set /A counter=0
set /A failedday=failedday+failed
if total NEQ 0 (set /A success=completed*100/total)
echo Success: %success%

Related

Bat Script Loop Date Range Format Input [duplicate]

This question already has an answer here:
How to generate succesive dates? (add N days to date)
(1 answer)
Closed last month.
I have bat script for loop function
#echo off set /p a="Start Date(yyyymmdd):"%=% set /p b="Finish Date
(yyyymmdd):"%=%
echo %a% echo %b%
echo start loop
FOR /L %%c IN (%a%,1,%b%) DO ( echo %%c
set inputan=%%c
call test_loopong.bat %inputan%
)
I need to run according to the range of start and end date input.
But from the script above, for example the start date is 20221231 and the end date is 20230103
will loop all numbers from 20221231, 20221232, 20221233......20230103
Please someone can help me.
Thanks
#ECHO Off
SETLOCAL
set /p "startdate=Start Date(yyyymmdd):"
set /p "finishdate=Finish Date (yyyymmdd):"
echo %startdate%
echo %finishdate%
IF %finishdate% lss %startdate% ECHO Invalid DATE range&GOTO :eof
echo start loop
FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
echo %%c
set /a inputan=%%c
call :test_loopong.bat %%c
)
)
GOTO :EOF
:test_loopong.bat
ECHO IN test_loopong : %%1=%1 inputan=%inputan%
GOTO :eof
I changed the variable names so that they are maintainable, 'though I've no idea what inputan means.
Added invalid date-range check.
Note syntax of set /p
Forget for the moment what for...%%y... does.
I used a set /a since %%c must be numeric.
Use set "var1=value" for setting STRING values - this avoids problems caused by trailing spaces.
I converted test_loopong.bat to an internal subroutine (call :name) for demonstration purposes to avoid having to generate another file.
I'm having that subroutine simply display the value of the variable inputan and the parameter %1. %%c can be delivered as a parameter to the subroutine (be it internal or external) but your syntax would appear to omit the parameter because of the delayed expansion trap - %var% will be replaced by the value of var at the time the outer loop (for...%%c) is encountered.
Now the for...%%y jiggery-pokery.
The command set /a inputan=%%c % 100 would set inputan to %%c mod 100. There's no importance about the variable name - that one's about to be assigned a different value again in a couple of lines.
When used in a for /f, batch will execute the set/a command and echo the result to the metavariable %%y.
However, = and % are special characters and need to be "escaped" (interpreted without their special meaning). Th escape character for most specials is caret (^) but for % is % itself.
The result of the calculation is assigned to %%y and we can then test that %%y is lss 32 - Less than 32, and also it is gtr 0 - Greater than 0. Only then do we call test_loopong.bat. This eliminates most non-dates
If you don't want to skip the non-dates, then remove the for...%%y line and delete one of the ) lines.
--- further thoughts ----
Suppressing the days 32..99 & 00 really only does half the job. Much better if we suppress months 13..99 & 00. The revision then would be (presenting just the main loop, minus the frippery)
FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
FOR /F %%e IN ('set /a inputan^=%%c %% 10000') DO IF %%e lss 1232 IF %%e gtr 100 (
FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
echo %%c
set /a inputan=%%c
call :test_loopong.bat %%c
)
)
)
Same principle, just dealing with months in place of days.
One slight problem with this method is that it's as slow as a wet week.
So - a different approach
SET /a yyyy=%startdate:~0,4%
SET /a mm1=1%startdate:~4,2%
SET /a dd1=1%startdate:~-2%
:loop2
SET /a inputan=%yyyy%0000+%mm1%00+dd1-10100
IF %inputan% gtr %finishdate% GOTO :eof
CALL :test_loopong.bat %inputan%
SET /a dd1+=1
IF %dd1% leq 131 GOTO loop2
SET /a dd1=101&SET /a mm1+=1
IF %mm1% leq 112 GOTO loop2
SET /a mm1=101
SET /a yyyy+=1
GOTO loop2
This sets yyyy to the year and mm1/dd1 to 100+(month/day). 100+ needs to be done since batch regards a numeric string that starts 0 as
octal hence August and September cause problems.
So - calculate inputan by tringing 4 0s to yyyy, adding 100*mm1 and dd1, then subtracting 10100 since mm1 is mm+100 and dd1 is dd+100.
If the resultant inputan is greater than the finish date, end the routine.
Test using inputan.
Next day - add 1 to dd1.
If the result is less than or equal to 131, we're fine.
Otherwise set dd1 to 101 and increment the month
Same recipe for mm1, limit is 112 and bump the year if required.
---- Further revision to deal with non-dates 31st Apr, Jun, Sep, Nov and Feb (include leap years) ---
#ECHO Off
SETLOCAL
set /p "startdate=Start Date(yyyymmdd):"
set /p "finishdate=Finish Date (yyyymmdd):"
echo %startdate%
echo %finishdate%
IF %finishdate% lss %startdate% ECHO Invalid DATE range&GOTO :eof
echo start loop
GOTO ver2
FOR /L %%c IN (%startdate%,1,%finishdate%) DO (
FOR /F %%e IN ('set /a inputan^=%%c %% 10000') DO IF %%e lss 1232 IF %%e gtr 100 (
FOR /F %%y IN ('set /a inputan^=%%c %% 100') DO IF %%y lss 32 IF %%y gtr 0 (
echo %%c
set /a inputan=%%c
call :test_loopong.bat %%c
)
)
)
GOTO :EOF
:ver2
SET /a yyyy=%startdate:~0,4%
SET /a mm1=1%startdate:~4,2%
SET /a dd1=1%startdate:~-2%
:loop2
SET /a inputan=%yyyy%0000+%mm1%00+dd1-10100
IF %inputan% gtr %finishdate% GOTO :eof
CALL :test_loopong.bat %inputan%
SET /a dd1+=1
SET /a inputan=yyyy %% 4
IF %mm1%==102 IF %dd1% gtr 129 (GOTO nextmonth) ELSE IF %inputan% neq 0 IF %dd1%==129 GOTO nextmonth
FOR %%e IN (104 106 109 111) DO IF %%e131==%mm1%%dd1% GOTO nextmonth
IF %dd1% leq 131 GOTO loop2
:nextmonth
SET /a dd1=101&SET /a mm1+=1
IF %mm1% leq 112 GOTO loop2
SET /a mm1=101
SET /a yyyy+=1
GOTO loop2
GOTO :eof
:test_loopong.bat
ECHO IN test_loopong : %%1=%1 inputan=%inputan%
GOTO :eof

Total of array in batch

I am trying to get an average of an array in this code:
set /a arr[%b%]=%i%
where the %b% is set from 0 and b=b+1 and loops until it hits a number. The numbers in this array could vary.
Now I need to get an average of this arr[%b%] so I can display it at the end of the whole code.
Thank you
You'll need to modify this based on the size of the array:
setlocal enabledelayedexpansion
set limit=10
set /a total=0
for /l %%a in (0, 1, %limit%) do set /a total+=!arr[%%a]!
set /a ave=%total%/%limit%
Echo Total: %total%
Echo Average: %ave%
And that should work for arr[0] to arr[10].
Monacraft answer is not bad ,but I prefer to calculate the array length.Here is a revised answer (plus added modulus)...
#echo off
setlocal enabledelayedexpansion
::::::::just a test array::::::::::::
set /a arr[1]=1
set /a arr[2]=1
set /a arr[3]=1
set /a arr[4]=7
set /a arr[5]=2
set /a arr[6]=1
:::::::::::::::::::::::::::::::::::::
set /a total=0
for /f "delims=" %%# in ('set arr[^|find /c "="') do set "limit=%%#"
for /l %%a in (0, 1, %limit%) do set /a total+=!arr[%%a]!
set /a ave=total/limit
set /a mod=total%%limit
Echo Total: %total%
Echo Average: %ave%.%mod%
Echo Average(no mod): %ave%
endlocal

Batch script - Assign variable in FOR-IF

I have a file with this output:
ANS8000I Server command: 'ru FailedReport'
Unnamed[1]
------------
9
Unnamed[1]
------------
110
Unnamed[1]
------------
101
I need to take those numbers, and assign it to three different variables. I made this script, but I can't make it to work... I always got "0" as result.
#echo off
setlocal enableextensions enabledelayedexpansion
set /A counter=0
SET /A failed=0
SET /A completed=0
SET /A total=0
for /F "tokens=1 skip=4" %%a in (C:\Users\Desktop\Aux.txt) do (
if "%counter%" EQU 5 (set /A failed=%%a)
if "%counter%" EQU 9 (set /A completed=%%a)
if "%counter%" EQU 13 (set /A total=%%a)
set /A counter+=1
)
echo "Failed: " %failed% >> C:\Users\Desktop\Result.txt
echo "Completed: " %completed% >> C:\Users\Desktop\Result.txt
echo "Total: " %total% >> C:\Users\Desktop\Result.txt
Could anyone help me with this? I tried a lot of combinations (variables with !, %, %%), but I still got the same result.
Thanks!!!
#ECHO OFF
setlocal enableextensions enabledelayedexpansion
set /A counter=0
SET /A failed=0
SET /A completed=0
SET /A total=0
for /F "tokens=1" %%a in (q24152955.txt) do (
ECHO !counter! %%a
if !counter! EQU 3 (set /A failed=%%a)
if !counter! EQU 9 (set /A completed=%%a)
if !counter! EQU 6 (set /A total=%%a)
set /A counter+=1
)
echo "Failed: " %failed%
echo "Completed: " %completed%
echo "Total: " %total%
GOTO :eof
I used a file named q24152955.txt containing your data for my testing.
In delayedexpansion mode, %var% refers to the original value of var - before the loop began execution and !var! is the dynamic value - as it changes.
"something" is never going to be equal to something because the quotes are significant. Quoted values are often used in this context in case the value itself is empty or contains special characters (especially spaces) - "" is a non-empty string.
for /f ignores empty lines. I've included a superfluous echo command to show which lines the for processes. Note that the value of counter is thus the sequential number of non-empty lines in the file, not the actual line number. Note also that a line containing just one (or more) spaces is not an empty line!
#ECHO off&cls
setlocal enabledelayedexpansion
set "$count=1"
for /f "delims=" %%a in (C:\Users\Desktop\Aux.txt) do (
if !$count!==4 set failed=%%a
if !$count!==7 set completed=%%a
if !$count!==10 set total=%%a
set /a $count+=1
)
(echo Failed : %failed: =%
echo Completed : %completed: =%
echo Total : %total: =%)> C:\Users\Desktop\Result.txt

How do I concatenate the value of a variable into the name of another in a batch file?

So I've been writing a batch file which backs up a certain file while cleaning old entries every so often. I've run into an issue where it would be simpler and more readable to store month lengths (for calculation purpose) (days1,days2,days3,etc.), and reference these by concatenating the word days with a variable which stores the month (1, 2, 3, etc.). Unfortunately, this never seems to reference the right variable correctly. Here's the relevant code, from a section calculating a date 28 days previously:
set days1=31
set days2=28
set days3=31
set days4=30
set days5=31
(etc.)
...
set pastmonthday=%curday%-28
set pastmonthmonth=%curmonth%
set pastmonthyear=%curyear%
if %pastmonthday% lss 0 (
set /a pastmonthmonth=%pastmonthmonth%-1
set /a pastmonthprevmon=1
)
if %pastmonthmonth%==0 (
set /a pastmonthyear-=1
set /a pastmonthmonth=12
)
set monthlengthvar=0
setlocal EnableDelayedExpansion
set tempmonthlengthvar=0
if %pastmonthday% lss 0 (set tempmonthlengthvar = !days%pastmonthmonth%!)
echo.%tempmonthlengthvar%
pause
for /F "delims=" %%A in (!tempmonthlengthvar!) DO (
endlocal
set "monthlengthvar=%%A"
)
set pastmonthday+=%monthlengthvar%
echo.%pastmonthday%
pause
...
The two echoes output 0 and -7, respectively. I can't figure out why this is, no matter how I've reworked it.
some errors (forgotten /a in set, quotes etc.)
#ECHO OFF &SETLOCAL disableDelayedExpansion
SET /a days1=31
set /a days2=28
set /a days3=31
set /a days4=30
set /a days5=31
set /a pastmonthday=22-28
set /a pastmonthmonth=2
set /a pastmonthyear=2014
if %pastmonthday% lss 0 (
set /a pastmonthmonth-=1
set /a pastmonthprevmon=1
)
if %pastmonthmonth% equ 0 (
set /a pastmonthyear-=1
set /a pastmonthmonth=12
)
set /a monthlengthvar=0
setlocal EnableDelayedExpansion
set /a tempmonthlengthvar=0
if %pastmonthday% lss 0 SET /a tempmonthlengthvar=!days%pastmonthmonth%!
ECHO(%tempmonthlengthvar%
for /F "delims=" %%A in ("%tempmonthlengthvar%") DO (
IF "!"=="" endlocal
set /a monthlengthvar=%%A
)
set /a pastmonthday+=monthlengthvar
ECHO(%pastmonthday%

Using an if statement inside a for loop

I am trying to make a batch file to solve the first Project Euler problem, http://projecteuler.net/problem=1, but I need an if statement inside my loop to check if n modulo 3 or 5 is 0. And the sum has suddenly stopped working.
My code:
echo off
set sum=0
for /l %%n in (1,1,999) do (
set a/ sum+=%%n *(only add if n%%3 == 0 or n%%5 == 0)*
)
echo %sum%
pause
Here is a very efficient solution, though it is a bit obfuscated:
#echo off
setlocal
set /a sum=0
for /l %%N in (1 1 999) do set /a "sum+=%%N/!((%%N%%5)*(%%N%%3))" 2>nul
echo %sum%
The expression (%%N%%5)*(%%N%%3) yields zero if %%N is divisible by 3 or 5, or non-zero if it is not divisible by either. The ! takes the inverse logical value, so 0 becomes 1, and non-zero becomes 0. Dividing %%N by that expression yields either %%N or a division by zero error. So simply add that entire expression to the sum, and redirect error messages to nul.
Final result - only numbers divisible by 3 or 5 are added :-)
#ECHO OFF
SETLOCAL
set /A sum=0
for /l %%n in (1,1,999) do (
CALL :modulo %%n
IF DEFINED addme set /a sum+=%%n
REM CALL echo %%n %%sum%% %%addme%%
)
echo %sum%
GOTO :EOF
:modulo
:: set addme if %1 %% 3 == 0 or %1 %% 5 == 0
SET /a addme = %1 %% 3
IF %addme%==0 GOTO :EOF
SET /a addme = %1 %% 5
IF %addme%==0 GOTO :EOF
SET "addme="
GOTO :eof
Simply pass each value to the :modulo routine in turn and set a flag value to (clear or not)
OR
#ECHO OFF
SETLOCAL enabledelayedexpansion
set /A sum=0
for /l %%n in (1,1,999) do (
SET /a mod=%%n %% 3
IF NOT !mod!==0 SET /a mod=%%n %% 5
IF !mod!== 0 set /a sum+=%%n
rem CALL echo %%n %%sum%%
)
echo %sum%
GOTO :EOF
which does the same thing using delayedexpansion.
And the sum has suddenly stopped working.
I think your sum stopped working because your set needs to have the slash in front of the 'a', and not behind it, like this:
SET /A sum+=%%n
Also, there isn't an OR operator in DOS Batch, so you'll need to use a nested IF for that. This worked for me:
echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set sum=0
for /l %%n in (1,1,999) do (
SET /A mod3=%%n%%3
SET /A mod5=%%n%%5
IF !mod3!==0 (
SET /A sum+=%%n
) ELSE (
IF !mod5!==0 (
SET /A sum+=%%n
)
)
)
echo %sum%
ENDLOCAL
If you need more help, check out Rob van der Woude's Scripting pages. Specifically, here is a link to his page on performing mathematical operations in DOS batch files.

Resources