TL; DR:
I came across the idea of ββusing a "For" loop and a "set" command to allow parsing of variables, which allowed me to create pseudo-arrays in both an ordered style and a linked list style, and, more importantly, pseudo-objects, akin to structures .
Typical Pseudo Array batch and how to analyze it:
SET "_Arr.Names="Name 1" "Name 2" ... "Name N"" FOR %A IN (%_Arr.Names%) DO @( Echo.%~A ) REM Results: REM Name 1 REM Name 2 REM ... REM Name N
Below we will make some Dumb Pseudo Arrays and manually ordered Pseudo Array, and also create an Ordered Pseudo Array that intercepts the output of the DIR command.
We also take Dumb Pseudo Arrays and convert them to Ordered (after removing the original Dumb Pseudo Array variables).
Then we update all ordered arrays so that they contain more elements manually.
Finally, we dynamically report some values ββfrom the array by executing a predefined For L loop for values ββfrom 7 to 9 and generating a random value to print the 4th example of the array value.
Remarks:
I am creating a variable to hold the method for adding members to make it easier to add.
I emphasize this, as this should facilitate understanding of how we make a minor transition from ordered arrays to pseudo objects.
@( SETLOCAL ENABLEDELAYEDEXPANSION ECHO OFF REM Manually Create a shortcut method to add more elements to a specific ordered array SET "_Arr.Songs.Add=SET /A "_Arr.Songs.0+=1"&&CALL SET "_Arr.Songs.%%_Arr.Songs.0%%" REM Define some 'dumb' Pseudo arrays SET "_Arr.Names="Name 1" "Name 2" "Name 3" "Name 4" "Name 5" "Name 6" "Name 7" "Name 8"" SET "_Arr.States="AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA" "HI" "ID" "IL" "IN" "IA" "KS" "KY" "LA" "ME" "MD" "MA" "MI" "MN" "MS" "MO" "MT" "NE" "NV" "NH" "NJ" "NM" "NY" "NC" "ND" "OH" "OK" "OR" "PA" "RI" "SC" "SD" "TN" "TX" "UT" "VT" "VA" "WA" "WV" "WI" "WY"" ) REM Manually Create One Ordered Array %_Arr.Songs.Add%=Hey Jude" %_Arr.Songs.Add%=The Bartman" %_Arr.Songs.Add%=Teenage Dirtbag" %_Arr.Songs.Add%=Roundabout" %_Arr.Songs.Add%=The Sound of Silence" %_Arr.Songs.Add%=Jack and Diane" %_Arr.Songs.Add%=One Angry Dwarf and 200 Solumn Faces" REM Turn All Pre-Existing Normal Pseudo Arrays into Element Arrays REM Since Ordered Arrays use Index 0, we can skip any manually created Ordered Arrays: FOR /F "Tokens=2 Delims==." %%A IN ('SET _Arr. ^| FIND /V ".0=" ^| SORT') DO ( IF /I "%%~A" NEQ "!_TmpArrName!" ( SET "_TmpArrName=%%~A" IF NOT DEFINED _Arr.!_TmpArrName!.Add ( REM Create a shortcut method to add more members to the array SET "_Arr.!_TmpArrName!.Add=SET /A "_Arr.!_TmpArrName!.0+=1"&&CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%" ) FOR %%a IN (!_Arr.%%~A!) DO ( CALL SET /A "_Arr.!_TmpArrName!.0+=1" CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%=%%~a" ) ) IF DEFINED _Arr.!_TmpArrName! ( REM Remove Unneeded Dumb Psuedo Array "_Arr.!_TmpArrName!" SET "_Arr.!_TmpArrName!=" ) ) REM Create New Array of unknown Length from Command Output, and Store it as an Ordered Array SET "_TmpArrName=WinDir" FOR /F "Tokens=* Delims==." %%A IN ('Dir /B /A:D "C:\Windows"') DO ( IF NOT DEFINED _Arr.!_TmpArrName!.Add ( SET "_Arr.!_TmpArrName!.Add=SET /A "_Arr.!_TmpArrName!.0+=1"&&CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%" ) CALL SET /A "_Arr.!_TmpArrName!.0+=1" CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%=%%~A" ) ) REM Manually Add additional Elements to the Ordered Arrays: %_Arr.Names.Add%=Manual Name 1" %_Arr.Names.Add%=Manual Name 2" %_Arr.Names.Add%=Manual Name 3" %_Arr.States.Add%=51st State" %_Arr.States.Add%=52nd State" %_Arr.States.Add%=53rd State" %_Arr.Songs.Add%=Live and Let Die" %_Arr.Songs.Add%=Baby Shark" %_Arr.Songs.Add%=Safety Dance" %_Arr.WinDir.Add%=Fake_Folder 1" %_Arr.WinDir.Add%=Fake_Folder 2" %_Arr.WinDir.Add%=Fake_Folder 3" REM Test Output: REM Use a For Loop to List Values 7 to 9 of each array and A Psuedo Rnadom 4th value REM We are only interested in Ordered Arrays, so the .0 works nicely to locate those exclusively. FOR /F "Tokens=2,4 Delims==." %%A IN ('SET _Arr. ^| FIND ".0=" ^| SORT') DO ( CALL :Get-Rnd %%~B ECHO. ECHO.%%~A 7 to 9, Plus !_Rnd
Example Results:
Results: Names 7 to 9, Plus 5 - Psuedo Randomly Selected * Element [7] of Names Pseudo Array = "Name 7" * Element [8] of Names Pseudo Array = "Name 8" * Element [9] of Names Pseudo Array = "Manual Name 1" * Random Element [5] of Names Pseudo Array = "Name 5" Songs 7 to 9, Plus 5 - Psuedo Randomly Selected * Element [7] of Songs Pseudo Array = "One Angry Dwarf and 200 Solumn Faces" * Element [8] of Songs Pseudo Array = "Live and Let Die" * Element [9] of Songs Pseudo Array = "Baby Shark" * Random Element [5] of Songs Pseudo Array = "The Sound of Silence" States 7 to 9, Plus 9 - Psuedo Randomly Selected * Element [7] of States Pseudo Array = "CT" * Element [8] of States Pseudo Array = "DE" * Element [9] of States Pseudo Array = "FL" * Random Element [9] of States Pseudo Array = "FL" WinDir 7 to 9, Plus 26 - Psuedo Randomly Selected * Element [7] of WinDir Pseudo Array = "assembly" * Element [8] of WinDir Pseudo Array = "AUInstallAgent" * Element [9] of WinDir Pseudo Array = "Boot" * Random Element [26] of WinDir Pseudo Array = "Fonts"
Initially, I would do something similar to Aacini, a simple string of variables with an incremental counter, manually or assigning them using a simple loop from a quick list of variables.
This was good for small 2-D arrays.
However, I find this a pain for long data arrays, especially when I need multi-valued content.
Not to mention when I need to dynamically map and populate content in these multidimensional arrays where simple use is violated there.
I found that it became difficult when you needed several arrays of information that you needed to update or add functions in all directions.
- , , , , .
, , , FTP-, X .
, :
Site.
.
( SETOCAL ECHO OFF REM Manage Sites: SET "Sites=13" SET "MaxAge=28" SET "Site.1="[IP]" "[User Name]" "[Password]" "[Path]"" SET "Site.2="[IP]" "[User Name]" "[Password]" "[Path]"" SET "Site.3="[IP]" "[User Name]" "[Password]" "[Path]"" REM ... SET "Site.11="[IP]" "[User Name]" "[Password]" "[Path]"" SET "Site.12="[IP]" "[User Name]" "[Password]" "[Path]"" SET "Site.13="[IP]" "[User Name]" "[Password]" "[Path]"" ) FOR /L %%L IN (1,1,%Sites%) DO ( FOR /F "Tokens=*" %%A IN ('CALL ECHO %%Site.%%L%%') DO ( Echo. Pulled this example from a more complex example of my actual code, so the example variables may not need this loop, but it won't hurt to have if they don't need the extra expansion. Call :Log CALL :DeleteFTP %%~A ) ) GOTO :EOF :DeleteFTP REM Simple ftp command for cygwin to delete the files found older than X days. SET "FTPCMD="%~dp0lftp" %~1 -u %~2,%~3 -e "rm -rf %~4%MaxAge% " FOR /F "Tokens=*" %%F IN ('"%FTPCMD% 2^>^&1"') DO @( ECHO.%%~F ) GOTO :EOF
, 13 , , , . ? , .
, 5, .
::... SET "Site.1="[IP]" "[User Name]" "[Password]" "[Path]" "[Site Name]"" ::...
, ( IP-, , ), 13 , .
::... SET "Site.1="[Site Name]" "[IP]" "[User Name]" "[Password]" "[Path]"" ::... FOR /F "Tokens=*" %%A IN ('CALL ECHO %%Site.%%L%%') ::... SET "FTPCMD="%~dp0lftp" %~2 -u %~3,%~4 -e "rm -rf %~5%MaxAge% " ::...
:
- , , , .
- , , , .
30, 40, 50 , , , , ..
, , , , , .
, / , , .
, , , .
? , :
, () cmd, .
IE " ", , . CMD -, , .
, , , , , :
eg: Site.[ID].[Object Property]=[Value, or array of values] Site .ID=[int] .Name=[string] .Path=[String] .MaxAge=[Int] .Details=[Array (String)] @( IP=[SubSting], Username=[SubString], Password[SubString])
, , , , , .
:
@( SETLOCAL ENABLEDELAYEDEXPANSION ECHO OFF SET "_SiteCount=0" SET "_SiteID=0" SET /A "_SiteID= !_SiteID! + 1" SET "Site.!_SiteID!.MaxAge=Day5Ago" SET "Site.!_SiteID!.Name=[SITE NAME HEADER FOR EMAIL]" SET "Site.!_SiteID!.Detail="[IP]" "[UserName]" "[Password]" "[Path]"" REM ... SET /A "_SiteID= !_SiteID! + 1" SET "Site.!_SiteID!.MaxAge=Day15Ago" SET "Site.!_SiteID!.Name=[SITE NAME HEADER FOR EMAIL]" SET "Site.!_SiteID!.Detail="[IP]" "[UserName]" "[Password]" "[Path]"" ) CALL :Main ( ENDLOCAL Exit /b %eLvl% ) :Main REM In some forms of these the order isn't meaningful, but in others you need to follows the order and so we just count he number of site objects by counting one of their properties. FOR /F %%A IN ('SET ^| FIND /I "Site." ^| FIND /I ".Name="') DO ( CALL SET /A "_SiteCount+=1" ) FOR /L %%L IN (1,1,34) DO ( CALL :PSGetDate_DaysAgo %%L ) FOR /L %%L IN (1,1,%_SiteCount%) DO ( SET "Site.%%L.Create=NONE" ) FOR /L %%L IN (1,1,%_SiteCount%) DO ( FOR /F "Tokens=*" %%A IN ('CALL ECHO ""%%Site.%%L.Name%%" %%Site.%%L.Detail%% "Site.%%L" "%%%%Site.%%L.MaxAge%%%%""') DO ( CALL ECHO CALL :DeleteFTP %%~A CALL :DeleteFTP %%~A ) ) CALL :SendMail "%EMLog%" "%_EMSubject%" GOTO :EOF :DeleteFTP REM ECHO.IF "%~7" EQU "%skip%" ( IF "%~7" EQU "%skip%" ( GOTO :EOF ) SET "FTPCMD="%~dp0lftp" %~2 -u %~3,%~4 -e "rm -rf %~5%~7 " SET "FTPCMD=%FTPCMD%; bye"" FOR /F "Tokens=*" %%F IN ('"%FTPCMD% 2^>^&1"') DO @( ECHO."%%F" ECHO."%%~F" REM CALL :Output "%Temp%\%~2_%~7.log" "%%F" %OP% "%Temp%\%~2_%~7.log" SET "FTPOut=%%~F" ) GOTO :EOF
, , , , , .
, , , , , .
SET "_GUID=^%Time^%_^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%" eg: %~n0.[ObjectName].[Object Property].[Object Sub Property]=[Value, or array of values] [Script Name] .[Object Name](May Hold Count of Names)=[int] .Name=[string] .Paths(May Hold Count of IDs)=[INT] .GUID=%_GUID% .Path=String .MaxAge=[Int] .Details=[Array (String)] @( IP=[SubSting], Username=[SubString], Password[SubString])
, , , , , .
, , , .
, FTP, , :
@( SETLOCAL ENABLEDELAYEDEXPANSION ECHO OFF SET /A "_SiteID= !_SiteID! + 1" SET "SiteName=SiteA" SET "%~n0.!SiteName!=%%_SiteID%% SET "%~n0.!SiteName!.SiteID=!_SiteID! SET "%~n0.!SiteName!.Paths="PathA" "PathB" "PathC" "PathD" "PathE"" ) CALL :CheckFTP [FTP Login variables from source object including Site ID] :CheckFTP REM Not necessary to assign Variables, doing this for exposition only: CALL SET "TempSiteName=%~6" CALL SET "TempPaths=%%%~n0.%~1.Paths%%" REM Clear the site Temp KB variables FOR \F "Tokens=2* Delims== " %%H IN (%TempPaths% "Total" "Temp") DO ( CALL SET /A "%%%~n0.%~1.Paths.%%~H.KB=0" ) FOR %%J IN (%TempPaths%) DO ( FOR /F "Tokens=1-2" %%F IN ('[FTP Command using source object options]') DO @( CALL :SumSite "%~6" "%%~F" "%%~G" FOR /F "Tokens=1,2,* delims=/" %%f IN ("%%~G") DO ( CALL :ConvertFolder "%~6" "%%~F" "%%~g" "%%~h" "%~6_%%~g_%%~h" ) ) ) FOR /F "Tokens=3,4,7 Delims==_." %%g IN ('SET ^| FIND /I "%~6_" ^| FIND /I ".KB" ^| FIND /I /V "_."') DO ( CALL :WriteFolder "%%g/%%~h" "%TmpFile%" "%~6_%%~g_%%~h" REM echo.CALL :WriteFolder "%%g/%%~h" "%TmpFile%" "%~6_%%~g_%%~h" ) CALL :ConvertSite "%~1" CALL :WriteTotalFolder "%~7" "%TmpFile%" "%~6" CALL :SendMail "%TmpFile%" "Backup_%~1" GOTO :EOF :SumSite CALL SET "TSumPaths=%%%~n0.%~1.Paths%% "Total"" FOR %%H IN (%TSumPaths%) DO ( CALL SET /A "%~n0.%~1.Paths.%%~H.KB=%%%~n0.%~1.Paths.%%~H.KB%%+%~2" ) :SumSite CALL SET "TSumPaths=%%%~n0.%~1.Paths%% "Total"" FOR %%H IN (%TSumPaths%) DO ( CALL SET /A "%~n0.%~1.Paths.%%~H.KB=%%%~n0.%~1.Paths.%%~H.KB%%+%~2" ) GOTO :EOF :ConvertFolder REM Convert Folder values to MB and GB SET /A "%~1.Temp.KB=%~2" CALL SET /A "%~1.Temp.MB=%%%~1.Temp.KB%%/1024" CALL SET /A "%~1.Temp.GB=(%%%~1.Temp.KB%%/1024)/1024" CALL SET /A "%~5.Temp.KB=%%%~5.Temp.KB%%+%~2" CALL SET /A "%~5.Temp.MB=%%%~5.Temp.KB%%/1024" CALL SET /A "%~5.Temp.GB=(%%%~5.Temp.KB%%/1024)/1024" GOTO :EOF :WriteFolder CALL :PickGMKBytes "%~1" "%~2" "G" "M" "K" "%%%~3.Temp.GB%%" "%%%~3.Temp.MB%%" "%%%~3.Temp.KB%%" GOTO :EOF :PickGMKBytes IF /I "%~6" NEQ "" ( IF /I "%~6"=="0" ( CALL :PickGMKBytes "%~1" "%~2" "%~4" "%~5" "%~6" "%~7" "%~8" ) ELSE ( CALL :Output "%~2" "%~6%~3 %~1" ) ) ELSE ( CALL :Output "%~2" "0B %~1" ) GOTO :EOF :ConvertSite CALL SET "TempPaths=%%%~n0.%~1.Paths%%" FOR %%V IN (%TempPaths% "Total") DO ( CALL SET /A "%~1.%%~V.MB=%%%~1.%%~V.KB%%/1024" CALL SET /A "%~1.%%~V.GB=(%%%~1.%%~V.KB%%/1024)/1024" ) GOTO :EOF
, , , , , , : , , , , , .. .
, , , , . , .