[Resolved] For loop to do something with all variables beginning with a string [also find variables order of appearance]

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
koko
Posts: 29
Joined: 13 Oct 2016 00:40

[Resolved] For loop to do something with all variables beginning with a string [also find variables order of appearance]

#1 Post by koko » 17 Sep 2019 18:40

I'm guessing this is relatively straightforward but my attempts have obviously been missing the mark. I have several variables beginning with a fixed string that change in quantity (ie: an unknown number of them) and I'm trying to set up a for loop that does something for each one beginning from the first one listed in the batch script (ultimately wanting to use them for a choice prompt).

Eg the original variables (unknown quantity but has at least one):

Code: Select all

set example-foo=something
set example-bar=else
Ultimately desired goal (after formatting and adding an increasing counter for each variable found, for a choice prompt):

Code: Select all

echo Select Example:
echo 1. foo
echo 2. bar
choice /c 12 /n
I found that the command set example- lists such variables (one for each new line) but most of the times I experimented with it in a for loop as the command (in (set example-) do) an error returned 'The system cannot find the file set.'. Eg:

Code: Select all

@echo off
setlocal enabledelayedexpansion

for /f "tokens=* delims= " %%a in (set example-) do (
   echo %%a
)
Is this what I should be using or is there an alternative method I should be looking at? Or have I just overlooked something obvious (wouldn't be the first time :p).
Last edited by koko on 18 Sep 2019 17:30, edited 1 time in total.

penpen
Expert
Posts: 1727
Joined: 23 Jun 2013 06:15
Location: Germany

Re: For loop to do something with all variables beginning/prefixed with a string

#2 Post by penpen » 17 Sep 2019 20:01

koko wrote:
17 Sep 2019 18:40
but most of the times I experimented with it in a for loop as the command (in (set example-) do) an error returned 'The system cannot find the file set.'.
You missed a pair of ' characters:

Code: Select all

@echo off
setlocal enableExtensions disableDelayedExpansion
set example-foo=something
set example-bar=else

for /f "tokens=* delims= " %%a in ('set example-') do (
   echo %%a
)
goto :eof
koko wrote:
17 Sep 2019 18:40
Is this what I should be using or is there an alternative method I should be looking at? Or have I just overlooked something obvious (wouldn't be the first time :p).
You could do that, but i prefer using variable names that mimic a c/c++/jave-like arrays and direct member selection operator (a dot):

Code: Select all

@echo off
setlocal enableExtensions disableDelayedExpansion
set "example[1].label=foo"
set "example[1].content=something"
set "example[2].label=bar"
set "example[2].content=else"
set "example.length=2"

setlocal enableExtensions enableDelayedExpansion
for /l %%a in (1, 1, !example.length!) do (
	echo %%~a. !example[%%~a].label!
)
endlocal

goto :eof
But that's all a matter of taste.
I use these variable names, because that looks more familar to me and i intuitively understand what they mean.
You should use something that you could read and understand easily.


penpen

koko
Posts: 29
Joined: 13 Oct 2016 00:40

Re: For loop to do something with all variables beginning/prefixed with a string

#3 Post by koko » 17 Sep 2019 22:41

penpen wrote:
17 Sep 2019 20:01
You missed a pair of ' characters
Ah, thank you. Tried double quotes but that became the literal string, didn't try single quotes.
penpen wrote:
17 Sep 2019 20:01
You could do that, but i prefer using variable names that mimic a c/c++/jave-like arrays and direct member selection operator (a dot)

You should use something that you could read and understand easily.
Mmm, in this particular case the variable positions can be re-arranged arbitrarily so the numbering of the variables is probably less useful unless one controls the order. Interesting format to keep in mind though nonetheless :)

koko
Posts: 29
Joined: 13 Oct 2016 00:40

Re: For loop to do something with all variables beginning/prefixed with a string

#4 Post by koko » 18 Sep 2019 03:35

koko wrote:
17 Sep 2019 22:41
in this particular case the variable positions can be re-arranged arbitrarily so the numbering of the variables is probably less useful unless one controls the order.
Hmm, turns out after adding more to test with that the variables are being ordered alphabetically during my for loop. Is there actually any way to sort them in the order they appear in the batch script itself?

Aacini
Expert
Posts: 1619
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: For loop to do something with all variables beginning/prefixed with a string

#5 Post by Aacini » 18 Sep 2019 08:56

No. There is no way to control the order in that SET command lists the defined variables; that is the reason because it is convenient to define different arrays with numerical indices...

I suggest you to review this topic...

Antonio

koko
Posts: 29
Joined: 13 Oct 2016 00:40

Re: For loop to do something with all variables beginning/prefixed with a string

#6 Post by koko » 18 Sep 2019 17:22

Aacini wrote:
18 Sep 2019 08:56
No. There is no way to control the order in that SET command lists the defined variables; that is the reason because it is convenient to define different arrays with numerical indices...

I suggest you to review this topic...

Antonio
The thing is, this will be used for some simple user settings so I'm not really counting on them to hand-number them each time they want the order changed. Achieved variable order of appearance in my batch script by using findstr instead.

Example script below for those who may find it useful. Keep in mind for this the variables are set using the explicit, original name only once in the script so findstr matches only the ones desired initially (before converting them each to separate variables numbered in order of appearance).

Code: Select all

@echo off
setlocal enabledelayedexpansion

set example-one=value
set example-two=value
set example-three=value
set example-four=value
set example-five=value

set count=0
for /f "delims=" %%a in ('findstr /r /c:"^set example-" "%~f0"') do (
    set /a count+=1
    for /f "tokens=1,2 delims==" %%a in ("%%a") do (
        set "varcount[!count!]=!count!"
        set "vartitle[!count!]=%%a"
        set "varvalue[!count!]=%%b"
        )
    )

echo Order of variable appearance in batch file:
for /l %%i in (1,1,!count!) do (
    set "vartitle[%%i]=!vartitle[%%i]:set =!"
    echo !varcount[%%i]! ^| !vartitle[%%i]! ^| !varvalue[%%i]!
    )

pause
endlocal

Aacini
Expert
Posts: 1619
Joined: 06 Dec 2011 22:15
Location: México City, México

Re: [Resolved] For loop to do something with all variables beginning with a string [also find variables order of appeara

#7 Post by Aacini » 19 Sep 2019 02:13

You may achieve the same result in simpler ways. For example:

Code: Select all

@echo off
setlocal enabledelayedexpansion

rem Below there is a method to define variables by putting them in a FOR command.

rem Optionally you may also define a list of variables this way:
rem set values="example-one=value" "example-two=value" "example-three=value" "example-four=value" "example-five=value"
rem and then modify the FOR command in this way:
rem for %%v in (%values%) do ...

set count=0
for %%v in ("example-one=value"
            "example-two=value"
            "example-three=value"
            "example-four=value"
            "example-five=value"
    ) do for /F "tokens=1,2 delims==" %%a in (%%v) do (
        set /a count+=1
        set "vartitle[!count!]=%%a"
        set "varvalue[!count!]=%%b"
    )
)

echo Order of variable appearance in batch file:
for /l %%i in (1,1,!count!) do (
    echo %%i ^| !vartitle[%%i]! ^| !varvalue[%%i]!
)

pause
endlocal
Antonio

koko
Posts: 29
Joined: 13 Oct 2016 00:40

Re: [Resolved] For loop to do something with all variables beginning with a string [also find variables order of appeara

#8 Post by koko » 19 Sep 2019 20:02

Aacini wrote:
19 Sep 2019 02:13
You may achieve the same result in simpler ways. For example
Interesting alternative, will keep it in mind. (Forum also seemed to be down for a number of hours, hope everything is alright).

Edit Also updated below my earlier script example to be more resilient to special characters in the batch file path when searching itself using findstr. Tested with a path containing ! !$%&()=^#';ä which works now. Some other characters didn't work however, such as ` and §.

From what I can tell from searches findstr doesn't have broad support for Unicode but the choking on the backtick may be a different issue.

Code: Select all

@echo off
setlocal enabledelayedexpansion

set example-one=value
set example-two=value
set example-three=value
set example-four=value
set example-five=value

rem obtain raw batch file path, accounting for special characters
setlocal disabledelayedexpansion
for %%f in (!cmdcmdline!) do (
    for %%i in ("%%~f") do set batchpath="%~f0"
    )
setlocal enabledelayedexpansion

set count=0
for /f "delims=" %%a in ('findstr /r /c:"^^set example-" !batchpath!') do (
    set /a count+=1
    for /f "tokens=1,2 delims==" %%a in ("%%a") do (
        set "varcount[!count!]=!count!"
        set "vartitle[!count!]=%%a"
        set "varvalue[!count!]=%%b"
        )
    )

echo Order of variable appearance in batch file:
for /l %%i in (1,1,!count!) do (
    set "vartitle[%%i]=!vartitle[%%i]:set =!"
    echo !varcount[%%i]! ^| !vartitle[%%i]! ^| !varvalue[%%i]!
    )

pause
endlocal

penpen
Expert
Posts: 1727
Joined: 23 Jun 2013 06:15
Location: Germany

Re: [Resolved] For loop to do something with all variables beginning with a string [also find variables order of appeara

#9 Post by penpen » 21 Sep 2019 18:26

koko wrote:
18 Sep 2019 17:22
The thing is, this will be used for some simple user settings so I'm not really counting on them to hand-number them each time they want the order changed.
I'm not sure what you mean there... .
In case you want the order in a simpler format, where you have to change only one index per entry in your example, then you might encapsulate that in an array, too:

Code: Select all

@echo off
cls
setlocal enableExtensions enableDelayedExpansion
set "example[1].label=foo"
set "example[1].content=something"
set "example[2].label=bar"
set "example[2].content=else"
set "example.length=2"

set "menuItem[1]=example[2]"
set "menuItem[2]=example[1]"
set "menuItem.length=2"

for /l %%a in (1, 1, !menuItem.length!) do for %%b in (!menuItem[%%~a]!) do (
	echo %%~a. !%%~b.label!
)

goto :eof
penpen

koko
Posts: 29
Joined: 13 Oct 2016 00:40

Re: [Resolved] For loop to do something with all variables beginning with a string [also find variables order of appeara

#10 Post by koko » 21 Sep 2019 19:29

penpen wrote:
21 Sep 2019 18:26
I'm not sure what you mean there... .
In case you want the order in a simpler format, where you have to change only one index per entry in your example, then you might encapsulate that in an array, too
That would make it simpler to change the order for the original hard-numbered array concept, true. Good example for that. The script I'm making is for rather novice users to edit if they need so my goal was more ease of changing order and adding new variables for user 'settings' (pre-set variables at the top of the script).

For example let's say the batch script comes with three 'settings' in the following order:

Code: Select all

set choice-ball=value
set choice-sun=value
set choice-land=value
I have the script obtain that list as it appears in that order and echo it for a choice prompt, with 'ball' and its value being first, 'sun' second, 'land' third. Then let's say a user wants to move the 'land' value to appear first for the prompt. Using this method all they'd have to do is cut and paste the 'land' line above the 'ball' line and it would now appear first (or if using a decent text editor shift the line upward using a hotkey). A simple change and the script would automatically account for it in the choice prompt.

Whereas if the initial variables had digits in the names it would require either re-numbering via a separate variable (eg: the menuItem example in the post above) which is a bit more involved particularly if settings want to be added/removed, or hand editing/re-numbering the digit order (or even re-arranging all the label/content pairings).

So in that sense I'm fond of the more straightforward findstr approach even if it has the caveat of having issues with certain characters in paths (I'll be including a regular set var for loop fall back approach in such cases). If it was just for my own use it wouldn't matter much the method, although honestly even I like just being able to simply re-arrange/add/remove the lines and have it reflected in the order :D

penpen
Expert
Posts: 1727
Joined: 23 Jun 2013 06:15
Location: Germany

Re: [Resolved] For loop to do something with all variables beginning with a string [also find variables order of appeara

#11 Post by penpen » 22 Sep 2019 02:06

You may encapsulate the initialization and building of the menues in function calls:

Code: Select all

@echo off
cls
setlocal enableExtensions enableDelayedExpansion
call :initMenu "choice"
call :addMenuItem "choice" "ball" "value 1"
call :addMenuItem "choice" "sun" "value 2"
call :addMenuItem "choice" "land" "value 3"

for /l %%a in (1, 1, !choice.length!) do (
	echo %%~a. !choice[%%~a].label!
)

goto :eof


:initMenu
:: %~1	name
set "%~1.length=0"
goto :eof


:addMenuItem
:: %~1	menue name
:: %~2	label
:: %~3	content
set /a "%~1.length+=1"
set "%~1[!%~1.length!].label=%~2"
set "%~1[!%~1.length!].content=%~3"
goto :eof
penpen

Post Reply