How to reference a variable that consists of metavariables, which require delayed expansion, to create a one-dimensional array in Batch

Multi tool use
Multi tool use


How to reference a variable that consists of metavariables, which require delayed expansion, to create a one-dimensional array in Batch



OS: Windows 10, Version: 10.0.17134.112



I was trying to reference a variable that consists of a dynamic variable, which requires delayed expansion, in the form of !string!variable!!. The problem I'm facing is it is being evaluated as [!string!][variable!!] rather than ![string][!variable!]!


!string!variable!!


[!string!][variable!!]


![string][!variable!]!



Here's an example of what I'm trying to do:


@echo off

setlocal EnableDelayedExpansion

::Sets variables - Items to be excluded, and an initial index number to reference these variables
set "_elem1=ex1"
set "_elem2=ex2"
set "_elem3=ex3"
set "_n=1"

::Builds a one-dimensional array excluding some items where item-set is arranged in a specific order
for %%e in (A B C ex1 D E F ex2 G H ex3 I J) do (
if not "!_elem!_n!!"=="%%e" (
set "_array=!_array!!_spc!"%%e""
set "_spc= "
) else (
set /a "_n+=1"
)
)

::Displays actual output
echo %_array%

::Displays DESIRED output
echo "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"

pause



Basically, what it does, or at least what it is supposed to do, is it builds a filtered one-dimensional array of items from for item-set by running a conditional block. If "!_elem!_n!!" is not equal to "%%e", the result for the current iteration is appended to the stored value of _array variable. Otherwise, it ignores the value from the current iteration and increments the index by 1, effectively changing the value of !_elem!_n!! on the next iteration.


for


"!_elem!_n!!"


"%%e"


_array


!_elem!_n!!



The problem is variable _n is dynamic and requires delayed expansion. What I'm trying to accomplish is for the variable !_elem!_n!! to be evaluated as ! _elem !_n! ! rather than !_elem! _n!!


_n


!_elem!_n!!


!


_elem


!_n!


!


!_elem!


_n!!



Upon researching, I've stumbled upon these sources:



The answers provided in the link are really valuable but the index used in the examples are not dynamic, and so, !_elem%_n%! would be fine in those situations but not if the index is dynamic. Also, a method using call was provided, which is clever, but call does not work with ifs.


!_elem%_n%!


call


call


if



I'm running out of ideas here. I'd really appreciate any ideas you could throw at this.



Thank you all very much!!





The solution is to use another for loop to gain another layer of variable expansion: for %%f in ("!_n!") do if not "!_elem%%~f!"=="%%e" ( ... ); see also this post
– aschipfl
Jul 3 at 6:40



for


for %%f in ("!_n!") do if not "!_elem%%~f!"=="%%e" ( ... )




3 Answers
3



Your approach had the flaw that you didn't compare each _elem with each %%e


_elem


%%e


Found


%%e


_elem


for /l


_elem


Found


:: Q:Test201873SO_51147577.cmd
@echo off & setlocal EnableDelayedExpansion
::Sets variables - Items to be excluded, and an initial index number to reference these variables
set "_elem1=ex1"
set "_elem2=ex2"
set "_elem3=ex3"
set "_spc="
::Builds a one-dimensional array excluding some items where item-set is arranged in a specific order
for %%e in (A B C ex1 D E F ex2 G H ex3 I J) do (
Set "Found="
For /l %%n in (1,1,3) do (
if "!_elem%%n!"=="%%e" Set Found=true
)
if Not defined Found (
set "_array=!_array!!_spc!"%%e""
set "_spc= "
)
)
::Displays actual output
echo %_array%
::Displays DESIRED output
echo "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
pause



Sample output:


> SO_51147577.cmd
"A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
"A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
Drücken Sie eine beliebige Taste . . .





Brilliant!! FOR /L makes it possible to compare elements to be excluded for each iteration of FOR item-set, which removes the complication (or flaw) of FOR item-set being in a specific order. Thank you very much for your help!! I really appreciate it..
– SpaghettiCode
Jul 3 at 7:35





I was thinking about a very minute detail. What if we add an else clause to the second if block and re-position set "found=" there, so that it only clears when necessary? What do you think?
– SpaghettiCode
Jul 3 at 20:24



else


if


set "found="





You want to check every entry in %%e separately if it has a match in any _elem, so the reset is necessary at the begin of the next entry.
– LotPings
Jul 3 at 20:28



The solution is to use another for loop to gain another layer of variable expansion:


for %%e in (A B C ex1 D E F ex2 G H ex3 I J) do (
for %%f in ("!_n!") do if not "!_elem%%~f!"=="%%~e" (
set "_array=!_array!!_spc!"%%~e""
set "_spc= "
) else (
set /A "_n+=1"
)
)



See also this post: Arrays, linked lists and other data structures in cmd.exe (batch) script.



An alternative is to move the if block into a sub-routine (let us call it :SUB). Therein you can use immediate expansion:


:SUB


for %%e in (A B C ex1 D E F ex2 G H ex3 I J) do (
call :SUB _n "%%~e"
)
:: ...
goto :EOF


:SUB
set "index=%~1"
if not "!_elem%index%!"=="%~2" (
set "_array=!_array!%_spc%"%~2""
set "_spc= "
) else (
set /A "%index%+=1"
)
goto :EOF



I did not analyse the logic of your script -- refer to LotPings' answer for that...





This deserves an upvote because this is the answer I was looking for, at least originally, and the right answer to the question I posted. But after seeing LotPing's answer, I realized it is better to compare each excluded item at each iteration, in which case the FOR item-set does not have to be in specific order. But thank you very much. Great answers, I'll keep these in mind..
– SpaghettiCode
Jul 3 at 8:08






I have to admit that I also like LotPings' answer more than mine, because he seems to think outside the box, while I was too focussed to the syntax issue...
– aschipfl
Jul 3 at 8:14



You may also use this approach: instead of define an array with the values to be excluded, you may write an array with such a values in the variable names. This makes the code simpler:


@echo off

setlocal EnableDelayedExpansion

::Sets variables - Items to be excluded as individual array elements

set "ex1=1"
set "ex2=1"
set "ex3=1"

::Builds a one-dimensional array excluding some items where item-set is arranged in a specific order
for %%e in (A B C ex1 D E F ex2 G H ex3 I J) do (
if not defined %%e (
set "_array=!_array!!_spc!"%%e""
set "_spc= "
)
)

::Displays actual output
echo %_array%

::Displays DESIRED output
echo "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"

pause



Of course, this method only works when the values are valid variable names, but you may embeed most characters in a variable name enclosing them in quotes: var["most chars here"]=1.


var["most chars here"]=1





This is by far the simplest yet the most ingenious approach I have ever seen. You're an expert as always—a Batch scripting master. I've seen your posts in the past and are all excellent source of information. I can see why you are sometimes defensive about your posts. It's all about passion. It's extremely difficult to make anything useful in Batch and it seems very easy for you. Thank you very much. I really appreciate your answer..
– SpaghettiCode
Jul 3 at 21:50





Thanks a lot for your kindly words! Do you know that you may change the selected answer if you wish? ;)
– Aacini
Jul 3 at 23:18


;)





Man, you're doing fine! The post authors should be the one begging for your valuable answers..
– SpaghettiCode
Jul 4 at 0:21






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

UMSX1qmzxRnAaqLVCZoMwfHRvK8QWMp,p AGA1tb5YqfM,F1jFdA,7Y 4
WnOO0qpcYx K 6n854yzI0 SiRwkGprqRC M,78AJB ZJGmn2mGGfjzO vI,G

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications