Batch array scripts, to make life easier
Posted: 04 Sep 2020 12:11
I often see questions on stackoverflow about defining "arrays" with batch. Here's a little something I whipped that I can use whenever I want to establish an array without having to code specifically for it.
The usage info and Error checking for is reasonably thorough making it simple to use
The script can be used to define, clear, append or modify array contents, including the value of array sub elements. It accepts parameters as args And / Or from files (Only one file's contents may be appended to the array at a time.)
Another script (macro) for searching an array for a given value:
Script for performing an alphanumerical order sort on array values:
Lastly a script to sort arrays containing Integer values from lowest to highest / highest to lowest value
Tempted to rework the switches and flow to combine all the scripts into one.
The usage info and Error checking for is reasonably thorough making it simple to use
The script can be used to define, clear, append or modify array contents, including the value of array sub elements. It accepts parameters as args And / Or from files (Only one file's contents may be appended to the array at a time.)
Code: Select all
@Echo off
Set "Usage=Echo/###&Echo/Call %~n0 "/A:Group Name" "element" "element..."&Echo/Call %~n0 "/A:Group Name" "/F:Filepath.ext"&Echo/Call %~n0 "/A:Group Name" REM : Clears the Array for the given Group Name&Echo/Call %~n0 "/A:Group Name" "element" "element..." "/O:3" REM : Overides Elements from the index supplied&Exit /B 1"
Set "UseErr=Echo/&Echo/Usage Error - Ensure command extensions and Delayed Expansion are enabled with: &Echo/Setlocal EnableExtensions EnableDelayedExpansion&Echo/ or from the command line:&Echo/CMD /V:On /K&Exit /B 1"
If Not "!Comspec!"=="%Comspec%" (%UseErr%)
(Set "SwParam="&Set "SwFParam="&Set "#ORP#=0"&Set "#FP#=0"&Set "Inset="&Set "#STDOut=0"&Set "GRPNm="&Set "!GRPNm!="&Set "SubEl="&Set "FlNm=%~n0") > Nul 2> Nul
If "%~1"=="" (%Usage:###=!FlNm! Usage:%) Else Call :GetArgs %*
If Errorlevel 1 Exit /B 1
If "!GRPNm!"=="" %Usage:###=/A:Groupname required%
If "!#ORP#!"=="1" Echo/!SwParam!|findstr /RX [0-9]* > Nul 2> Nul
If not "!SwParam!"=="" If Errorlevel 1 (%Usage:###=O:!SwParam! #Arg invalid. Only Integers accepted.%)
If "!#ORP#!"=="1" Set "#!GRPNm!=0"
If "!#%GRPNm%!"=="" Set "#!GRPNm!=0"
If "%#FP#%"=="1" (
If exist "!SwFParam!" (
For /F "Delims=" %%G in (!SwFParam!)Do If Not "%%~G"=="" (
For %%x in ("!GRPNm![!#%GRPNm%!]")Do (
Setlocal DisableDelayedExpansion
If "%#STDOut%"=="1" Echo/%%~x=%%~G
Endlocal & Set "%%~x=%%G"
)
Set /A "#!GRPNm!+=1" > Nul
)
) Else (%Usage:###=/F:!SwFParam! Invalid path%)
)
If not "!Inset!"=="" (
For %%G in (!Inset!)Do (
For %%x in ("%GRPNm%[!#%GRPNm%!]")Do (
Setlocal DisableDelayedExpansion
If "%#STDOut%"=="1" Echo/%%~x=%%~G
Endlocal & Set "%%~x=%%~G"
)
If Not "!SubEL!"=="" Set "%%~G=!SubEl!"
Set /A "#!GRPNm!+=1" > Nul
)
) Else (
If Not "%#FP#%"=="1" (
For /F "Tokens=1,2 Delims==" %%I in ('Set %GRPNm%')Do Set "%%~I=" > Nul 2> Nul
Set "#!GRPNm!=" > Nul 2> Nul
)
)
Exit /B 0
:GetArgs
If "%~1" == "" Exit /B 0
Set "Param=%~1"
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/D" > Nul 2> Nul && (Set "#STDOut=1"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/A:" > Nul 2> Nul && (Set "GRPNm=!Param:*/A:=!"&(If "!Param:*/A:=!"=="" %Usage:###=/A:Groupname required%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/O:" > Nul 2> Nul && (Set "SwParam=!Param:*/O:=!"&(If Not "!Param:/O:=!"=="" (Set "#ORP#=1")Else %Usage:###=/O:#Arg not Supplied%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/F:" > Nul 2> Nul && (Set "SwFParam=!Param:*/F:=!"&(If Not "!Param:/F:=!"=="" (Set "#FP#=1")Else %Usage:###=/F:Filepath.ext not Supplied%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/S:" > Nul 2> Nul && (Set "SubEl=!Param:*/S:=!"&(If "!Param:/S:=!"=="" %Usage:###=/S:Sub Element not Supplied%)&Shift&Goto :GetArgs)
Set Inset=!Inset! %1
Shift&Goto :GetArgs
Rem ::: Index count for each array GROUP stored in #GRPNm
Code: Select all
@echo off & Setlocal DisableDelayedExpansion
(Set LF=^
%= Above Empty lines Required =%)
Set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
::: { Array Search Macro <{Search Value}> <{Array Class Name}>
Set Search.Array=For %%n in (1 2) Do if %%n==2 (%\n%
For /F "Tokens=1,2 Delims={}" %%G in ("!Search.Item!") Do (%\n%
For %%s in ("%%~G") do (%\n%
For /F "USEBACKQ Tokens=1,2 Delims==" %%i in (`"Set %%~H["`) Do (%\n%
For /F "USEBACKQ Tokens=* Delims=" %%f in (`Echo("%%~j"^^^|%__AppDir__%Findstr.exe /I "%%~s"`) do (%\n%
If /I "%%~s" == "%%~f" (Echo %%~f found in %%~i = %%~j)%\n%
)%\n%
)%\n%
)%\n%
)%\n%
) Else Set Search.Item=
::: }
Set Search.Time=Echo/!Time!
Setlocal EnableDelayedExpansion
(For /L %%A in (1,2,3) do For /L %%B in (1,1,10) do Set /A ArrayName[%%A][%%B]=%%A * %%B)&REM Example Array
Set "ArrayName[2][8]=test"& Set "ArrayName[1][6]=string check"
%Search.Time% %= Search via Subroutine =%
For %%A in (3 5 8 12 test string "String Check") do Call :Search.Array "%%~A" ArrayName
%Search.Time% %= Search via Macro =%
For %%A in (3 5 8 12 test string "String Check") do %Search.Array%{%%~A}{ArrayName}
%Search.Time%
%Search.Array%{18}{ArrayName}
%Search.Time%
Pause & Endlocal & Exit /B
:Search.Array <Search Value> <Array Class Name>
(For %%S in ("%~1") do (
For /F "USEBACKQ Tokens=1,2 Delims==" %%A in (`"Set %~2["`) Do (
For /F "USEBACKQ Tokens=* Delims=" %%F in (`Echo("%%~B"^|%__AppDir__%Findstr.exe /I "%%~S"`) do (
If /I "%%~S" == "%%~F" (Echo %%~S found in %%~A = %%~B)
)&REM remove /I switch from FindStr if case sensitivity required
)
)) & Exit /B
Code: Select all
@Echo Off
Set "Usage=Echo/&Echo/%~n0 ["/F:filepath.ext" ^| "/A:Array Group Name"] & Exit /B 1"
IF "%~1"=="" %Usage%
IF "%~1"=="/?" %Usage%
Set "Inset=%~1"
Set "Switch=%Inset:~1,1%"
Call Set "Inset=%%Inset:/%Switch%:=%%"
Echo/%Switch%|Findstr /LIC:F > Nul && (
(For /F "UseBackQ Delims=" %%G in (`Type "%Inset%" ^| Sort`)Do (Echo/%%~G)) 2> Nul || (Echo/Invalid Filepath:"%Inset%"&%Usage%)
Exit /B 0
)
If Not "!Comspec!"=="%Comspec%" (Echo/&Echo/Usage Error - Ensure Delayed Expansion is enabled with:&Echo/Setlocal EnableDelayedExpansion& Exit /B 1)
Echo/%Switch%|Findstr /LIC:A > Nul && (For /F "Tokens=1,2 Delims==" %%G in ('Set %Inset%')Do Echo/%%H)>"%TEMP%\__Sort.txt"
Set "#$#=0"
(For /F "UseBackQ Delims=" %%G in (`Type "%TEMP%\__Sort.txt" ^| Sort`)Do (
For %%x in ("%Inset%[!#$#!]") Do (
Setlocal DisableDelayedExpansion
Endlocal & Set "%%~X=%%~G"
)
Set /A "#$#+=1"
)
)
Del /Q "%TEMP%\__Sort.txt"
Exit /B 0
Rem ::: Sorts STRINGS alphanumericaly. Not suited to Integer strings of varying length.
Rem ::: Can Sort text files or Arrays
Rem ::: With the manner sort process strings, when numerical strings are sorted Single digits will be treated as a higher value than multiple digits that
Rem ::: begin with a lesser value, as the sort is applied on the basis of character value in the string position, not the overall strings value.
Rem ::: For a given position in a string Character sort order is: [0-9][a-z]
Rem ::: Case is ignored
Code: Select all
@ECHO OFF
Set "UseErr=Echo/&Echo/Usage Error - Ensure command extensions and Delayed Expansion are enabled with: &Echo/Setlocal EnableExtensions EnableDelayedExpansion&Echo/ or from the command line:&Echo/CMD /V:On /K&Exit /B 1"
If Not "!Comspec!"=="%Comspec%" (%UseErr%)
(Set "GRPNm="&Set "S_Offset="&Set "#STDOut="&Set "indNm="&Set "nGRPNm="&Set "#Order="&Set "Inset="&Set "Usage=Echo/###&Echo/%~n0 /A:Groupname /I:Indexname [/H^|/L]&Exit /B 1") > Nul 2> Nul
Call :GetArgs %*
If Errorlevel 1 Exit /B 1
If "!GRPNm!"=="" %Usage:###=/A:Groupname required%
If "!nGRPNm!"=="" %Usage:###=/N:New Groupname required%
If "!IndNm!"=="" %Usage:###=/I:Index Name required%
If Not "%#Order%"=="" (Call :Sort%#Order% !nGRPNm! !indNm! !Inset!) Else (%Usage:###=Sort Order Required /H or /L%)
Exit /B 0
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Subroutines for Population of Arrays with numeric values in sorted order.
:sortL <Element_VarName> <Element_Index_VarName> <Variable Names containing the values to be Sorted and Populated to the Array>
REM Adjust array Index Number to account for Element_VarName and Element_Index_VarName:
Set "%2=0"
FOR %%P In (%*) DO If Not "%%P"=="%1" If Not "%%P"=="%2" If Not "%%P"=="" (
Set "%1[!%2!]=!%%P!"
Set /A "%2+=1"
)
REM Sort the Array using an Offset and Temporary variable to exchange values within nested For Loops.
For /L %%a In (1,1,!%2!) Do (
Set /A "S_Offset=%%a - 1"
For /L %%b IN (0,1,%%a) DO (
If not %%b==%%a For %%c in (!S_Offset!) DO (
IF !%1[%%c]! LEQ !%1[%%b]! (
Set "tmpV=!%1[%%c]!"
Set "%1[%%c]=!%1[%%b]!"
Set "%1[%%b]=!tmpV!"
)
)
)
)
Set /A %2-=1
If "!#STDOut!"=="1" For /L %%G in (0 1 !%2!)Do Echo/%1[%%G]=!%1[%%G]!
Exit /B 0
:sortH <Element_VarName> <Element_Index_VarName> <Variable Names containing the values to be Sorted and Populated to the Array>
REM Adjust array Index Number to account for Element_VarName and Element_Index_VarName:
Set "%2=0"
FOR %%P In (%*) DO If Not "%%~P"=="%~1" If Not "%%~P"=="%2" If Not "%%P"=="" (
Set "%1[!%2!]=!%%~P!"
Set /A "%2+=1"
)
REM Sort the Array using an Offset and Temporary variable to exchange values within nested For Loops.
For /L %%a In (1,1,!%2!) Do (
Set /A "S_Offset=%%a - 1"
For /L %%b IN (0,1,%%a) DO (
If not %%b==%%a For %%c in (!S_Offset!) DO (
IF Not !%1[%%c]! LSS !%1[%%b]! (
Set "tmpV=!%1[%%c]!"
Set "%1[%%c]=!%1[%%b]!"
Set "%1[%%b]=!tmpV!"
)
)
)
)
Set /A %2-=1
If "!#STDOut!"=="1" For /L %%G in (0 1 !%2!)Do Echo/%1[%%G]=!%1[%%G]!
Exit /B 0
:GetArgs
If "%~1" == "" (
(For /F "Tokens=1,2 Delims==" %%G in ('Set !GRPNm![')Do Set "Inset=!Inset! %%G") > Nul 2> Nul || (%Usage:###=Usage Error - Target Array is not defined%)
Exit /B 0
)
Set "Param=%~1"
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/H" > Nul 2> Nul && (Set "#Order=H"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/L" > Nul 2> Nul && (Set "#Order=L"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/D" > Nul 2> Nul && (Set "#STDOut=1"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/N:" > Nul 2> Nul && (Set "nGRPNm=!Param:*/N:=!"&(If "!Param:*/N:=!"=="" %Usage:###=/N:New Group Name required%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/A:" > Nul 2> Nul && (Set "GRPNm=!Param:*/A:=!"&(If "!Param:*/A:=!"=="" %Usage:###=/A:Group Name required%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/I:" > Nul 2> Nul && (Set "IndNm=!Param:*/I:=!"&(If "!Param:*/I:=!"=="" %Usage:###=/A:Index Name required%)&Shift&Goto :GetArgs)
Shift&Goto :GetArgs