So, the question title pretty much says it all.
What is the most efficient way to go through a list of numbered variables and find out which one contains the largest number.
I have no idea of how to do this without a good 20 lines of code, so instead I'll write some example code:
#echo off
for /l %%i in (1,1,10) do set /p var_%%i=Insert number:
::code here that finds out which variable is larger...
echo The largest number is... %largest_number%
#echo off
setlocal EnableDelayedExpansion
for /l %%i in (1,1,10) do set /p "var_%%i=Insert number %%i: "
set largest_number=%var_1%
for /l %%i in (2,1,10) do if !var_%%i! gtr !largest_number! set largest_number=!var_%%i!
echo The largest number is... %largest_number%
The most efficient solution for this problem will always be of linear time complexity, that is O(n). That is because there is no real way to divide & conquer this task, as all elements must checked, demanding at least O(n) time complexity.
The following batch program will demonstrate this task with both numbers and letters.
#echo off
setlocal enabledelayedexpansion
set max=0
for %%A in (1,2,99,3,4) do (
set n=%%A
if !n! GTR !max! set max=!n!
)
echo Greatest number: %max%
set max=0
for %%A in (A,C,B,Z,G) do (
set n=%%A
if !n! GTR !max! set max=!n!
)
echo Greatest letter: %max%
Related
In my batch I want to copy a variable amount of source- to target destinations.
I want to define like this:
#setlocal EnableDelayedExpansion
set source1="C:\folder1"
set target1="f:\folder1"
set source2="C:\folder2"
set target2="f:\folder2"
...
set sourcen="C:\foldern"
set targetn="f:\foldern"
Dependently from a defined amount of folders
set numFolder=5
I want to go through the folders in a loop:
set /a COUNT=0
:LOOP
echo %COUNT%
set /a COUNT+=1
rem write the NAME of the parameter variable (source1,source2 etc.) in nameor
set "nameor=source%COUNT%"
rem write the VALUE of the parameter variable (source1,source2 etc.) into origin ("C:\folder1", "C:\folder2")
set "origin=%nameor%"
echo %origin%
if %COUNT% lss %numFolder% goto LOOP
When I show
echo %nameor%
I get what I expectet: source1, source2 etc.
but
echo %%%origin%%%
only provides
source1
instead of the expected value
"C:\folder1"
I thought, that I could resolve this by using DelayedExpansion but what did I miss?
To avoid confusion for me, I change the "origin" to "source". E.g. set "origin=%nameor%" changed to set "source=%nameor%".
To print out "C:\folder1" to "C:\foldern", you should use echo !%source%!, else you will just see "source1" to "sourcen".
Your problem is just about array element management. Try this:
#echo off
setlocal EnableDelayedExpansion
rem Define the two arrays
set i=0
for %%a in ("C:\folder1=f:\folder1"
"C:\folder2=f:\folder2"
"C:\foldern=f:\foldern") do (
set /A i+=1
for /F "tokens=1,2 delims==" %%b in (%%a) do (
set source!i!="%%a"
set target!i!="%%b"
)
)
rem Show up to numFolder elements of both arrays
set numFolder=5
for /L %%i in (1,1,%numFolder%) do (
echo %%i- Source%%i=!source%%i!, Target%%i=!target%%i!
)
The first part is equivalent to your series of individual element assignments. In this way is easier to add new pairs of values.
For further description on array management in Batch files, see: Arrays, linked lists and other data structures in cmd.exe (batch) script
How can I increment part of a variable name?
EG. i want to increment
filename holds something like mmddyyyy-prev01-Database.mdb
and I'm trying to rename it to mmddyyyy-prev02-Database.mdb
With the code
Setlocal EnableDelayedExpansion
set /a nextFileName=!fileName:~0,13!!fileName:~13!+1
and I get the error
Missing operator.
I am using this to make a batch sub that will recursively rename the prevXX items so that the newest one is always prev01. I'm also doing regular setlocal in my method to keep the variables from getting mixed up between the deeper calls
I'm going the hard way:
#ECHO OFF &SETLOCAL disableDelayedExpansion
FOR /f "delims=" %%x IN ('DIR /b /a-d /o-n *-prev*-Database.mdb') DO (
FOR /f "tokens=1-3*delims=v-" %%a IN ("%%~x") DO (
FOR /f "tokens=*delims=0" %%e IN ("0%%c") DO (
FOR /f %%f IN ('SET /a %%e+1') DO (
IF %%f LEQ 9 (
ECHO REN "%%~x" "%%~a-%%~bv0%%~f-%%~d"
) ELSE (
ECHO REN "%%~x" "%%~a-%%~bv%%~f-%%~d"
)
)
)
)
)
Just remove the ECHOs to make it working.
SET /A won't allow you do this.
You'll have to break up into two lines, like this:
SET BaseFileName=!FileName:~0,13!
SET /A Counter=!FileName:~13!+1
Then, put the pieces back together:
SET NextFileName=%BaseFileName%%Counter%-Database.mdb
NOTE: This will not handle your leading 0...you'll have to write more code for that.
...
set filename=mmddyyyy-prev01-Database.mdb
call :nextname
ren %filename% %newname%
...
:nextname
set /a newname=1%filename:~13,2%+1
set newname=%filename:~0,13%%newname:~-2%%filename:~15%
goto :eof
Whether you'd use ren %filename% %newname% or ren !filename! !newname! is a matter of context. You've posted insufficient code to be certain. If, as I suspect, you are executing the ren in a loop, then you would need the !var! form and delayedexpansion (with which you appear familiar.) Within the subroutine :nextname, the %var% form should be used.
but remember that you need to rename your existing files in reverse-alphabetical order, so
mmddyyyy-prev03-Database.mdb becomes mmddyyyy-prev04-Database.mdb
mmddyyyy-prev02-Database.mdb becomes mmddyyyy-prev03-Database.mdb
mmddyyyy-prev01-Database.mdb becomes mmddyyyy-prev02-Database.mdb
On the batch script I'm currently working on, I've encountered a bit of a problem.
What I want to happen is to set a variable as itself, but after it to be followed by a percentage mark, a letter, a number from a for /l (#,#,#) loop, then another percentage sign.
My code is currently as follows;
set value1=1
set value2=10
for /l %%a in (%value1%,1,%value2%) do (
set variable1=%variable1%%b%%a%
)
This doesn't give me a value for %variable1% at all, even after looping this 10 times. I've tried adding 'variable1= ' (without apostrophes) to the top, however that gave me the same result. After searching around, I figured that I should try and cancel out the %'s which are before the 'b' and after the 'a' - using %'s in front of them -,and my code ended up like this;
set value1=1
set value2=10
set variable1=
for /l %%a in (%value1%,1,%value2%) do (
set variable1=%variable1%%b%%a%
)
This is the closest I got, however %variable1% would change the value to '%b1%', then '%b2%', then '%b3%', etc. Instead of tiling them up next to each other.
My desired result would be for, by the end of the loop, %variable1% to have a value of; %b1%%b2%%b3%%b4%%b5%%b6%%b7%%b8%%b9%%b10%
Where is my code going wrong? It seems that it should give me my desired output, however quite clearly, it's not.
Thanks in advanced,
Try this:
#echo off
setlocal EnableDelayedExpansion
set value1=1
set value2=10
set variable1=
for /l %%a in (!value1!,1,!value2!) do (
set percent=%%
set variable1=!variable1!!percent!b%%a!percent!
)
echo !variable1!
You will have to add setlocal EnableDelayedExpansion as this will helps to expand the variable at execution time rather than at parse time.
I am currently working on a game in batch script and in one place, I need to make a multiplication of decimals. The problem is, the end result is always 0.
This is the code:
#echo off
echo Calcultating New Values
echo ...
ping localhost -n 2 >nul
set /p coal_price_buy_brt=<coal_price_buy_brt.wss
set /p coal_ind_buy=<coal_ind_buy.wss
cls
echo First Values :
echo ################################
echo ## Coal Price Brutto ## %coal_price_buy_brt% ##
echo ################################
echo ## Coal Index Buy ## %coal_ind_buy% ##
echo ################################
ping localhost -n 3 >nul
echo %coal_price_buy_brt%
echo %coal_ind_buy%
set ENABLEDELAYEDEXPANSION=coal_price_buy_net
set /p coal_price_buy_net=<calc %coal_price_buy_brt%*%coal_ind_buy%
echo Complete Table :
echo ################################
echo ## Coal Price Brutto ## %coal_price_buy_brt% ##
echo ################################
echo ## Coal Index Buy ## %coal_ind_buy% ##
echo ################################
echo ## Coal Price Netto ## %coal_price_buy_net% ##
echo ################################
The file data are:
coal_price_buy_brt = 150
coal_ind_buy = 0.84
EDIT :
4 years after this post, i'm now in IT Studies and realize that there is a difference between integers and floats in coding...
Thanks for having helped me back then !
The arithmetic operations of SET /A command can only manage integer numbers. Imagine you have a calculator that does NOT have the key for decimal point. How could you achieve this operation: 150*0.84? Well, if you know that the second value is always less than one with two decimals, you may execute 150*84 instead and insert a decimal point before the second digit (from right to left) of the result:
#echo off
set coal_price_buy_brt=150
set coal_ind_buy=0.84
rem Convert coal_ind_buy to integer
set coal_ind_buy=%coal_ind_buy:0.=%
rem Execute the multiplication
set /A result=coal_price_buy_brt*coal_ind_buy
echo Result as integer: %result%
echo Result as fixed point with two decimals: %result:~0,-2%.%result:~-2%
If the values may have integer part, then you may achieve the appropriate conversion to integer values, execute the multiplication, and insert the decimal point in the right place; however, you always must select a fixed number of decimal places ("fixed point arithmetic"), unless you want to convert the values to floating point (with an exponent of ten) and achieve all the apropriate conversions!
For further details about fixed point arithmetic operations in Batch, see: http://www.dostips.com/forum/viewtopic.php?f=3&t=2704&p=12523#p12523
I know this is an older question, but I have had a similar question come up with some scripting of my own. Perhaps my answer can still help someone out there with the same/similar question. My question to myself was, "How can use floating point decimal numbers in my batch script?" After much pondering and researching other personal questions on StackOverflow, I came up with the following example script. It pretty much converts a floating point number into a fraction in the form of two variables that can be used in the rest of your script. It can be used in tandem with this answer https://stackoverflow.com/a/20531384/2464491 to a similar question.
#echo off
setlocal EnableExtensions
setlocal EnableDelayedExpansion
REM This is how I do a block comment.
goto SOF
========Begin Comment========
Title: deciTest.bat
This batch script checks to see if the number inputed is an interger or a floating point number.
If it is a floating point number, it determines to how many decimal places up to 4096 places.
It then informes the user of how to use the floating point number in arithmatic equations.
Of course, if you include within your script, you can simply call upon the !intOut! and
!multiplier! variables elswhere in your script.
=========End Comment=========
:SOF
REM Check to see if the user supplied a number.
if "%1"=="" (
REM If not, tell them how to use the file.
echo Usage: deciTest.bat [number]
echo.
echo [number] The number to check. Enter either an integer
echo or a floating point number.
echo.
goto eof
)
REM Assign the user input to variable decNum
set decNum=%1
REM Plop the number into a file
echo !decNum!>decNum.tmp
REM Check to see if there is a decimal point
findstr /c:"." decNum.tmp >null
REM If it is found, the number is a floating point number
REM So lets make it so we can use it.
if %errorlevel%==0 (
REM Separate our Characteristic (before the .) and Mantissa (after the .)
for /f "tokens=1-18* delims=." %%a in (decNum.tmp) do (
REM Count the length of our Mantissa (How may decimal places?)
set "s=%%b"
set "s=!s!#"
set "decPlaces=0"
for %%P in (4096 2048 1024 512 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "decPlaces+=%%P"
set "s=!S:~%%P!"
)
)
REM Inform the user of our findings.
echo %%a.%%b is a floating point number with !decPlaces! decimal places
call :Integrate
echo.
REM Create the variable !intOUt! for use elswhere in the code
set /a intOut=%%a*!multiple!+%%b
REM Tell the user how to use this particular floating number
echo Your batch file can use !intOut! in your arithmatic equations.
echo Simply divide your result by !multiple!.
)
) else (
REM If it aint floatin', it's an integer
echo %1 is an integer
)
goto eof
:Integrate REM Create the !multiple! variable to be used elsewhere in the script
set count=!decPlaces!
set multiple=1
:startloop
set /a multiple*=10
set /a count-=1
if not !count!==0 goto startloop
:eof
The code demonstrates how to handle floating point numbers. Essentially, it turns floating point numbers into fractions (!intOut!/!multipler!). If you adjust your arithmetic a bit. Multiply by !intOut!, then send !intOut!/!multiplier! with however many decimal places you want to the example script found here: https://stackoverflow.com/a/20531384/2464491
I hope this helps anyone who has run into the same problem when trying to work with floating point numbers in a batch script. Sure it's not designed to work with such numbers, but you can always script your way around the problem.
You can call this batch file to do a mathematical evaluation.
Name it vbs.bat and then use call vbs 150*0.84 and the result will be in a variable called %val%
#echo off
>"%temp%\VBS.vbs" echo Set fso = CreateObject("Scripting.FileSystemObject") : Wscript.echo (%*)
for /f "delims=" %%a in ('cscript /nologo "%temp%\VBS.vbs"') do set "val=%%a"
del "%temp%\VBS.vbs"
Batch mathematics is INTEGER, hence 0.84 will either be interpreted as 0 or as an invalid number.
You may use an hybrid Batch-JScript file as described in this answer: looking for a way to calculate logarithm in a DOS batch file
This method allows you to evaluate any floating point operation, including logarithms, square roots, etc.
#if (#CodeSection == #Batch) #then
#echo off
rem Evaluate floating point expressions via JScript, for example:
call :Expr result=%coal_price_buy_brt%*%coal_ind_buy%
echo %result%
goto :EOF
:Expr result=expression
for /F "delims=" %%a in ('Cscript //nologo //E:JScript "%~F0" "%2"') do set "%1=%%a"
exit /B
#end
WScript.Echo(eval(WScript.Arguments.Unnamed.Item(0)));
For further details on available JScript mathemathic operations, see: http://msdn.microsoft.com/en-us/library/ie/b272f386(v=vs.94).aspx
This is the new Script and it Still Doesn't Work
I Get The syntax of the command is incorrect.
on FOR /F "USEBACKQ tokens=*" %%A IN (TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command") DO (
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "C:\Windows\System32\tasks\at%num%" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "C:\Windows\System32\tasks\at!num! ^| FIND "Command"`) DO (
set var=%%A
ECHO %var%
SET /a num=%num%+1
PAUSE
)
GOTO:START
To understand your code, I'm going to break it down into logic first then try to solve it. Let me know if I miss a detail...
Set num var to 0
Begin :Loop
set num var to its current value ::NOT NEEDED - You've specified this prior to the GOTO
increment num var by +1
if myfolder\at* file exists then read at%num% and find a string then output that line to %tmp%\1.txt ::Need quotations on file location.
set F var to the line stored in %tmp%\1.txt
set F="%%F: =%%" ::Please explain what you are trying to do with this command.
set F to start on 10th character and remove the last 11 characters from the line.
echo the variable
If it doesn't exist, exit, but if it does return to :Loop
You should tell us what you are attempting. If it is as simple as saving a variable from a text file output, set F=<file.txt will work. If it didn't, then something happened prior to that command. Still... what is set F="%%F: =%%"?
Unless you are using a FOR loop variable, there is no need to use %% on each end of the variable.
If this were a FOR loop, it would look like this:
SETLOCAL ENABLEDELAYEDEXPANSION
set num=1
:START
IF NOT EXIST "myFolder\at%num%.txt" (GOTO:EOF)
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE "myFolder\at%num%.txt" ^| FIND /i "string"`) DO (
PAUSE
SET var=%%A
ECHO !var!
PAUSE
SET var=!var: =!
ECHO !var!
PAUSE
SET var=!var:~10,-11!
ECHO !var!
PAUSE
SET /a num=!num!+1
ECHO !num!
PAUSE
)
GOTO:START
One good practice to check if commands are working, such as SET, insert an ECHO on the variable and a PAUSE right after each time you believe the variable should be changed. This will track what has changed on the variable so you can see if your command was correct and the changes were made.
I'd suggest using Batch's inbuilt function for loops, see here.
Conditionally perform a command for a range of numbers
Syntax
FOR /L %%parameter IN (start,step,end) DO command
Or maybe iterating over files in a folder would be better for what you are trying to do?
Loop through files (Recurse subfolders)
Syntax
FOR /R [[drive:]path] %%parameter IN (set) DO command
Or iterating over file contents?
Loop command: against a set of files - conditionally perform
a command against each item.
Syntax
FOR /F ["options"] %%parameter IN (filenameset) DO command
FOR /F ["options"] %%parameter IN ("Text string to process") DO command
This site has plenty of examples here which should point you in the right direction.
There are a few issues with your code, I've amended as follows to get the variable populated with the contents of the temp file.
set num=0
:Loop
set /a num=%num%+1
if exist "myFolder\at*" (
TYPE "myFolder\at%num%" | FINDSTR "\<Command\>" > "%temp%\1.txt"
set /P F=<"%TEMP%\1.txt"
Echo %F%
Pause
)
I don't know if this is the problem, but have you tried enabling:
setlocal enabledelayedexpansion
Then, inside the loop (or the IF(...)), you use !foo! to signify environment variables instead of %foo%.
See setlocal /? and set /? for more information.