Thanks to Aacini, I now have a way to sort variables from greatest to least.
Link:
Comparing and ordering multiple numbers in batch
However, if 2 or more of my variables are the same value, they won't be sorted. I'm trying test to see if two variables in the set are equal. I tried using if statements against each variable in any combination I could think of, but that isn't very efficient and is hard to change.
Is there a way I can achieve this?
#echo off
setlocal EnableDelayedExpansion
set speed1=190
set speed2=78
set speed3=78
set speed4=23
rem Get the descending order of previous elements via "order" array
for /L %%i in (1,1,4) do (
set /A num=1000-speed%%i
set order!num!=%%i
)
rem Show the elements of "speed" array in descending order
for /F "tokens=2 delims==" %%i in ('set order') do (
echo speed%%i = !speed%%i!
)
Output will only display:
speed1 = 190
speed3 = 78
speed4 = 23
Excuse me. I don't know if you are really interested to know if two elements have the same value, or just to fix the bug of my previous solution (that don't include the elements with the same value), so I opted for solve previous bug:
#echo off
setlocal EnableDelayedExpansion
set speed1=190
set speed2=78
set speed3=78
set speed4=23
rem Get the descending order of previous elements via "order" array
REM Insert a second index to differentiate elements with the same value
for /L %%i in (1,1,4) do (
set /A num=1000-speed%%i
set order[!num!][%%i]=%%i
)
rem Show the elements of "speed" array in descending order
for /F "tokens=2 delims==" %%i in ('set order') do (
echo speed%%i = !speed%%i!
)
#echo off
setlocal enableextensions enabledelayedexpansion
set speed1=190
set speed2=78
set speed3=78
set speed4=23
for /f "usebackq tokens=1,2 delims=/" %%a in (`
cmd /q /e /c "for /f tokens^=1^,2^ delims^=^= %%c in ('set speed') do (set /a %%d + 10000000 & echo /%%c)"
^| sort /r
`) do (
set /a "value=%%a-10000000"
echo %%b=!value!
)
Related
Want to remove the duplicate values from machines variable in below batch file:
#echo off
set machines=node1,node2,node3,node2,node4,node1,node7,node6,node4
Expected output:
node1,node2,node3,node4,node6,node7
One way to accomplish your task:
Iterate the machines with a for and set them to an array,
this overwrites doublette entries.
Read the (alpha sorted) array back and store in the original variable (requires delayed expansion).
:: Q:\Test\2018\09\20\SO_52417320.cmd
#Echo off & Setlocal EnableDelayedExpansion
Set machines=node1,node2,node3,node2,node4,node1,node7,node6,node4
:: clear array machine[], then fill it
For /f "tokens=1 delims==" %%M in ('Set machine[ 2^>Nul') do Set "%%M="
For %%M in (%machines%) do Set "machine[%%M]=%%M"
Set machine[
Echo:
Set "machines="
For /f "tokens=2 delims==" %%M in ('Set machine[') do Set "machines=!machines!,%%M"
Echo:%machines:~1%
Sample output:
> SO_52417320.cmd
machine[node1]=node1
machine[node2]=node2
machine[node3]=node3
machine[node4]=node4
machine[node6]=node6
machine[node7]=node7
node1,node2,node3,node4,node6,node7
A short way to do it (this doesn't sort the machines variable, only removes the duplicates):
#echo off& setlocal EnableDelayedExpansion
set machines=node1,node2,node3,node2,node4,node1,node7,node6,node4
set "tmac=,"& for %%a in (%machines%) do if "!tmac:,%%a,=!"=="!tmac!" set "tmac=!tmac!%%a,"
set machines=%tmac:~1,-1%
In my opac_one-hit*.log I have 3 columns with numbers which are separated with ;
I want to find and rename the duplicated numbers in the third column and make the repeated numbers look like number_1... number_2
#ECHO OFF
SETLOCAL enabledelayedexpansion
for /r %%# in ("opac_one-hit*.log") do (
FOR /F "usebackq skip=3 tokens=1,3 delims=;" %%G IN ( "%%~f#" ) DO ( echo %%H >> liste.txt
)
)
Sample from opac_one-hit*.log:
"F96B1606";"216618711"; "BV499630491";
"F96B1607";"216618878"; "BV499630823";
"F96B1661";"216653304"; "BV49843883X";
"F96B1690";"216796148"; "BV49843883X";
Result:
the duplicated number in the third column should look like this "BV49843883X_1" If there are two duplicates then BV49843883X_1 and BV49843883X_2
You did not specified the desired output. This Batch file is a starting point:
#echo off
setlocal EnableDelayedExpansion
for %%# in ("opac_one-hit*.log") do (
for /F "usebackq tokens=3 delims=; " %%G in ("%%~f#") do (
echo "%%~G!N3[%%~G]!"
set /A "C3[%%~G]+=1"
set "N3[%%~G]=_!C3[%%~G]!"
)
)
This is the output:
"BV499630491"
"BV499630823"
"BV49843883X"
"BV49843883X_1"
Sadly you haven't shown exactly what your output should be, so I'll have to leave it to you to complete the task.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
:: remove variables starting #
FOR /F "delims==" %%a In ('set # 2^>Nul') DO SET "%%a="
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q49821253.txt"
SET "outfile=%destdir%\outfile.txt"
REM for /r %%a in ("%filename1%") do (
for %%a in ("%filename1%") do (
FOR /F "usebackq tokens=1,3 delims=;" %%G IN ( "%%~fa" ) DO (
CALL :bumpcount %%H
)
)
GOTO :EOF
:bumpcount
SET "col3=%~1"
(
IF DEFINED #%col3% (
SET /a #%col3%+=1
ECHO "%col3%_!#%col3%!"
) ELSE (
echo %1
SET /a #%col3%=0
)
)>> "%outfile%"
GOTO :eof
Note that I've changed the filenames to suit my system, removed the skip from the file-analyser and replaced the for/r with a plain vanilla for for testing.
The for /f to remove variables starting # needs to be moved to the line before the for...%%G... if you want to restart the numbering at the start of each new file. Don't use ::-comments within a loop, use REMcomments instead.
First, clear all # variables. then, on each line, pass column3's contents to a subprocedure called :bumpcount
:bumpcount sets the variable col3 to the value of column3, removing the enclosing quotes. If the variable #+column3 is defined, then we have encountered this value in the past, so increment it and append the new count-of-repeats to the contents of column3; otherwise, just output the value as suplied and set %+column3 to 0, indicating that it's been seen before and starting the count for that particular value's suffix.
Note the (...) surrounding the if defined statement. This gathers all output to the redirected destination.
Since you didn't explicitly show the desired output, I simply reproduced column3 without the terminal ; as I assume it appeared from your original code.
I have two variable length arrays of values, TargetName[] and TargetCpu[], which I need to return across the ENDLOCAL boundary. I've tried the following, but only the first value on the first array gets returned.
for /L %%i in (0,1,%MaxIndex%) do (
for /f "delims=" %%j in (""!TargetName[%%i]!"") do (
for /f "delims=" %%k in (""!TargetCpu[%%i]!"") do (
endlocal
set TargetName[%%i]=%%j
set TargetCpu[%%i]=%%k
)
)
)
Below is a print of the values returned.
Number Targets: 3
TargetName[0]: "Computer1"
TargetCpu[0] : "x64"
TargetName[1]: "!TargetName[1]!"
TargetCpu[1] : "!TargetCpu[1]!"
TargetName[2]: "!TargetName[2]!"
TargetCpu[2] : "!TargetCpu[2]!"
I've read about everything I can find, but nothing I've tried works for a variable length array.
#echo off
setlocal
set "MaxIndex=6"
call :CreateArrays
set TargetName
set TargetCPU
goto :EOF
:CreateArrays
setlocal EnableDelayedExpansion
for /L %%i in (1,1,%MaxIndex%) do (
set /A TargetName[%%i]=!random!, TargetCpu[%%i]=!random!
)
rem Return the arrays to the calling scope
set "currentScope=1"
for /F "delims=" %%a in ('set TargetName[ ^& set TargetCPU[') do (
if defined currentScope endlocal
set "%%a"
)
exit /B
set target>tempfile
rem insert your endlocal here
for /f "delims=" %%a in (tempfile) do set "%%a"
set target
the first set will list all variable names that start target into a tempfile.
Then execute your endlocal
then read each line of the file, which is of the form name=value and execute it prefixed by the set keyword.
Final set is to display results.
clearing up the tempfile isyour affair. Naturally, if you have other elements you don't want restored, you could use for instance
set targetname>>tempfile
set targetcpu>>tempfile
This question already has an answer here:
Batch recursing through folders & populating an array
(1 answer)
Closed 6 years ago.
Looking to parse out the path from a specific point & then use that to populate the dynamic array.
Example:
Folder tree:
C:\Main\folder1
C:\Main\folder2\folder2-1
C:\Main\folder3\folder3-1\folder3-2
Desired result:
Array[1]=folder1
Array[2]=folder2
Array[3]=folder2\folder2-1
Array[4]=folder3
Array[5]=folder3\folder3-1\
Array[6]=folder3\folder3-1\folder3-2
This is the working code below which returns fine but in full paths:
#echo off
setlocal EnableDelayedExpansion
SET folders=C:\Main
rem Populate the array with existent files in folder
set i=0
for /r "%folders%" /d %%a in (*) do (
set /A i+=1
set list[!i!]=%%a
)
set foldnum=%i%
rem Display array elements
for /L %%i in (1,1,%foldnum%) do (SET array[%%i]=!list[%%i]!)
for /F "tokens=2 delims==" %%f in ('set array[') do echo %%f
You pass an absolute path to the FOR loop. But even with a relative path the FOR loop does too much and converts it to an absolute path.
The trick here is to replace the absolute path in the FOR loop.
Create a copy of the loop variable in a real variable
set AA=%%a
Then replace prefix+backslash by nothing in the list "array'
set list[!i!]=!AA:%folders%\=!
full fixed code:
#echo off
setlocal EnableDelayedExpansion
SET folders=C:\Main
rem Populate the array with existent files in folder
set i=0
for /r "%folders%" /d %%a in (*) do (
set /A i+=1
rem create a copy of the loop variable in a real variable
set AA=%%a
rem replace prefix+backslash by nothing in a the list "array"
set list[!i!]=!AA:%folders%\=!
)
set foldnum=%i%
rem Display array elements
for /L %%i in (1,1,%foldnum%) do (SET array[%%i]=!list[%%i]!)
for /F "tokens=2 delims==" %%f in ('set array[') do echo %%f
then you get all the dirs of %folders% in a relative way.
A little bit of Tom Foolery.
#echo off
setlocal EnableDelayedExpansion
SET folders=C:\Main
subst B: %folders%
B:
set i=0
for /r /d %%G in (*) do (
set /A i+=1
FOR /F "tokens=* delims=\" %%H IN ("%%~pnG") do set "array[!i!]=%%~H"
)
C:
subst B: /D
set foldnum=%i%
rem Display array elements
for /F "tokens=2 delims==" %%f in ('set array[') do echo %%f
pause
I have a batch file that is passed commands in the form of a string array from a Java file. The commands contain something like the following:
String[] commands = {"A",
"B",
"C",
"C:\users\user\Documents",
"C:\users\user\Pictures"}
The commands array is dynamic, as it changes every time the java program is run. In the batch file, I create variables to take the values of the first three elements (A, B, and C in this case). Then I need to shift the directory strings to take up the first three elements of the array. Here is the batch code I have so far:
#echo off
setlocal enableDelayedExpansion
set /A paramCount=0
for %%x in (%*) do (
set list[!paramCount!]=%%x
set /A paramCount=paramCount+1
)
set argA=%list[0]%
set argB=%list[1]%
set argC=%list[2]%
set /A old=0
set /A new=!old!+3
for /F "tokens=2 delims==" %%a in ('set list[') do (
echo old=!old!
echo new=!new!
set list[!old!]=!list[%new%]!
echo !list[%old%]!
set /A old=!old!+1
set /A new=!new!+1 )
The problem I am having is with the line set list[!old!]=!list[%new%]!. As you can see, I have delayed expansion enabled. However, the !!'s are needed for the list[...] variable that is emulating an element in an array. However, I believe I need to use delayed expansion for "new" as well. What am I to do in this case? Or perhaps that's not the actual problem? The "old" and "new" variables are incrementing correctly, but the echo !list[%old%]! line returns the same value every time. I expect the same issue exists in that line, with "old"--It should have !'s surrounding it but the !'s are already being used for the list[...] variable. So what happens if you need nested !'s in a statement? Thanks for the aid!
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /A paramCount=-3
for %%x in (%*) do (
set list[!paramCount!]=%%x
set /A paramCount=paramCount+1
)
set argA=%list[-3]%
set argB=%list[-2]%
set argC=%list[-1]%
for /F "tokens=2 delims==" %%a in ('set list[-') do SET "%%a="
SET arg
SET list
ENDLOCAL
echo==================
setlocal ENABLEDELAYEDEXPANSION
set /A paramCount=0
for %%x in (%*) do (
set list[!paramCount!]=%%x
set /A paramCount=paramCount+1
)
set argA=%list[0]%
set argB=%list[1]%
set argC=%list[2]%
set /A old=0
set /A new=!old!+3
for /F "tokens=2 delims==" %%a in ('set list[') do (
echo old=!old!
echo new=!new!
CALL set list[%%old%%]=%%list[!new!]%%
CALL ECHO(%%list[!old!]%%
set /A old=!old!+1
set /A new=!new!+1
)
SET arg
SET list
GOTO :EOF
This should work for you - the easy way and the hard way.