Echo batch file arrays using a variable for the index? - arrays

If I have a batch file and I am setting arrays with an index that is a variable
#echo off
SET x=1
SET myVar[%x%]=happy
How do I echo that to get "happy" ?
I've tried
ECHO %myVar[%x%]%
ECHO %%myVar[%x%]%%
ECHO myVar[%x%]
But none of them work.
It works fine if I use the actual number for the index
ECHO %myVar[1]%
But not if the index number is also a variable

SET x=1
SET myVar[%x%]=happy
call echo %%myvar[%x%]%%
set myvar[%x%]
for /f "tokens=2* delims==" %%v in ('set myvar[%x%]') do #echo %%v
setlocal enableDelayedExpansion
echo !myvar[%x%]!
endlocal
I would recommend you to use
setlocal enableDelayedExpansion
echo !myvar[%x%]!
endlocal
as it is a best performing way

There is a special ! character in batch to deal with your situation. Use echo !myVar[%x%]!, from How to return an element of an array in Batch?. ! means delayed expansion. The variable myVar will not get expanded until after %x% is, yielding the expression you want.

one way you can do this is to use
call echo %%myVar[%x%]%%
call lets you put variables in places where they wouldn't normally work, if you use the double percents

Related

Batch: for loop not working

Code is this:
#echo off
set str=abcd
for /L %%i in (1,1,4) do set str=%str%%str%
echo %str%
At the end, I want str to be a long string. But its value is only abcdabcd. What is wrong? Why is this happening?
#Barış, please use the search bar before asking duplicated questions.
In the script, you will need delayedexpansion, to start it, use setlocal enabledelayedexpansion.
#echo off
setlocal enabledelayedexpansion
set str=abcd
for /L %%i in (1,1,4) do set str=!str!!str!
echo %str%
Notice %str% becomes !str!(! means to expand the variable at command run-time, not phasing time.)
Another way of doing this is mentioned by #JosefZ
for /L %%i in (1,1,4) do call set str=%%str%%%%str%%
This uses call's special variable expansion trick.

Batch-File Variable Part of Another Variable

Okay so let's say I have the following code
set playerlevel=5
set x=player
echo %x%level
I want the output to be "5", is that possible?
dbmitch's answer is good for integers, but if you want to display strings or integers, you can simply use delayed expansion.
#echo off
setlocal enabledelayedexpansion
set playerlevel=5
set x=player
echo !%x%level!
Note that if the code is located inside of a code block (i.e. enclosed in parentheses), the syntax is slightly different.
#echo off
setlocal enabledelayedexpansion
REM This is just an example code block to show off the alternate syntax with the %%s
for /L %%A in (1,1,1) do (
set playerlevel=5
set x=player
call echo %%!x!level%%
)
You can get what you want by using a combination of enabledelayedexpansion and the set /a to emulate an EVAL function
Try this:
#echo off
setlocal enabledelayedexpansion
set playerlevel=5
set x=player
set /a varx = "%x%level"
echo %varx%

variable is not assigned in for loop despite EnableDelayedExpansion

I have the following batch script that is supposed to generate filenames on the fly. Unfortunately I can't get the function to assign a return value to filename. Each echo returns an empty line.
#echo off
setlocal EnableDelayedExpansion
for /l %%i in (0,1,1) do (
call :create_filename %%i filename
echo(!%filename%!
)
pause
:create_filename
set "base=My test file"
if %1 GTR 0 set "base=%base% (%1)"
set "%~2=%base%.txt"
GOTO :eof
Using delayed variables require you to refer to them with !Var! syntax rather than %Var% syntax. %Var% remains expanded at readtime. !Var! are expanded at execution time. Set DelayedExpansion just turns on support for!Var!.

Splitting string using delayed expansion limitation

When I was testing a script I came across this issue when trying to extract characters from a string using batch. I have simplified it into a simple example. t.txt just contains the word hello.
#echo off
setlocal enabledelayedexpansion
set a=0
set b=1
for /f %%a in (t.txt) do (
set x=%%a
echo !x:~!a!,!b!!
set /a x+=1
)
pause >nul
The problem is, the variable x needs to be accessed using delayed expansion, and because I am updating the values of a and b through the loop these also need to be accessed using delayed expansion.
When trying to use the variables a and b to split the string they all need delayed expansion, but the order of the ! marks means that it is not parsed the way I intended!
CMD will expand my command as !x:~!, !,! and !!, instead of expanding the inner ones first. Obviously I can't use %'s either.
The only way I have found to get around this is to call an external function that isn't in the loop, so I can use %'s.
#echo off
setlocal enabledelayedexpansion
set a=0
set b=1
set v=
for /f %%a in (t.txt) do (
set x=%%a
call :RETURN x
set /a x+=1
)
pause >nul
:RETURN
set v=%1
echo %v:~!a!,!b!%
Is there any way of getting cmd to parse my command how I need it to, or this just a limitation I will have to use call for?
Simply transfer variables a and b to FOR variables.
#echo off
setlocal enabledelayedexpansion
set a=0
set b=1
for /f %%a in (t.txt) do (
set "x=%%a"
for /f "tokens=1,2" %%A in ("%a% %b%") do echo !x:~%%A,%%B!
REM this line makes no sense if x=hello: set /a x+=1
)
pause >nul
Mixing delayed and normal expansion will work.
#echo off
setlocal EnableDelayedExpansion
set a=0
set b=1
for /f %%L in (t.txt) do (
set "x=%%L"
echo !x:~%A%,%B%!
)

Temporarily interrupt SETLOCAL

I have a script that has a lot of use of the SETLOCAL ENABLEDELAYEDEXPANSION command, so I start the script off that way (less headaches). However, it does not allow you to use the ! character without escaping each instance of it (and I want to create a long line of !s for an error logging section =D ) and I don't want to escape every one of them.
Is there a way to temporarily break out of SETLOCAL, then reenter it keeping all previously created variables within the original SETLOCAL?
For example:
SETLOCAL ENABLEDELAYEDEXPANSION
set var=HELLO
ECHO %var%
ENDLOCAL
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO %var%
The 2nd ECHO will not give you the previous value of var
EDIT: ^ will not allow you to escape the ! inside SETLOCAL ENABLEDELAYEDEXPANSION
setlocal DisableDelayedExpansion
set var=Value! with! many! Bangs!
setlocal EnableDelayedExpansion
echo !var!
You can nest it like Aacini shows it.
Or you can use the return technic or escape ! inside a EnableDelayed block with ^^!
Setlocal EnableDelayedExpansion
echo 1^^!^^!^^!^^!^^!^^!^^!
REM *** Or use a self removing quote
echo !="! 2^!^!^!^!^!^!
Setlocal DisableDelayedExpansion
echo 3 !!!!!!!!
set var=Hello
(
endlocal
rem Bring the value behind the endlocal barrier
set var=%var%
)
echo var is still there, %var%
The return technic can also be used for exclamation marks, but then it is a bit more complex.
It can be found at Make an environment variable survive ENDLOCAL

Resources