3

How to use variables in variables? This code:

set newvar=%var%var2%%

doesn't work. So, what to do? I can't write my program without it.

  • I think I understand what you want, and if so the answers below misinterpret it: if I'm right, you want var2 to hold a value such as A, so you want newvar to be set to the contents of varA. The only way I have found to make CMD double-parse is to use echo set newvar=%%var%var2%>temp.cmd, then .\temp.cmd. A bit unwieldy, but it does work. – AFH Jun 30 '14 at 21:21
  • Sorry @mihi - I think your answer does the same thing, but I have not encountered usebackq before, and I can't properly work through the syntax. I'll look again when I'm less tired. – AFH Jun 30 '14 at 21:37

3 Answers3

5

A relatively slow method. The CALL command provides an extra level of variable expansion. The percents around the outer variable name are doubled to delay the expansion until after the inner variable has been expanded.

@echo off
setlocal
set "var1=value"
set "var2=1"
call set "newvar=%%var%var2%%%"

A much better method is to use delayed expansion. It must be first enabled with SETLOCAL ENABLEDELAYEDEXPANSION. The variable within percents is expanded when the line is parsed. The variable within exclamation points is expanded after parsing, just before the line is executed.

@echo off
setlocal enableDelayedExpansion
set "var1=value"
set "var2=1"
set "newvar=!var%var2%!"
dbenham
  • 11,384
  • Hmm. I’m puzzled. According to Super User’s time stamps, you posted this before I posted my answer – but I don’t remember seeing it before now. – Scott - Слава Україні Jul 03 '14 at 13:19
  • @Scott - My answer has indeed been here all along, around 12 hours before yours was posted. – dbenham Jul 03 '14 at 13:47
  • Well, maybe I had a problem with my browser or my Internet connection. The point is, I didn’t steal from your (very elegant) answer – if I’d seen it, I wouldn’t have posted mine – and I did upvote you. BTW, I tried set newvar=%var!A!% – so close, but no cigar! – Scott - Слава Україні Jul 03 '14 at 14:10
  • 1
    @Scott - No worries :-) The logic behind why %var!A!% fails and !var%A%! works is pretty simple once you know the order of the various expansion phases. – dbenham Jul 03 '14 at 17:00
1

Generally, I'd try to avoid scenarios like this. While it is possible, it is far from performant and not very easy to read either - basically you'd have to parse the output of the set command.

set index=9
set var9=Goal

echo %var9%
for /F "usebackq tokens=1* delims==" %I in (`set`) do if "%I" == "var%index%" set result=%J
echo %result%
mihi
  • 3,437
  • Ouch. This sort of works, but it could fail if looking for VAR1 and VAR10 also exists. It could be greatly optimized, and made more fool proof. But there are much better (and far simpler) methods. – dbenham Jul 01 '14 at 14:14
  • @dbenham while I have to admit that the other solutions are easier (but probably did not work in NT4 which was the last OS where I had more contact with batch programming - later I always tried to use vbs or PoSH), I don't see why VAR10 can be of any problem - the delims splits %I% to before = and %J% to after =, and = cannot be in variable names AFAIK. – mihi Jul 01 '14 at 16:26
  • Sorry, my bad. You are absolutely correct. I was getting mixed up with the optimization of using in (set var%index%) that I had rummaging around in my head. The only situation where your solution wouldn't work is if the value began with =. I'm not sure when delayed expansion was introduced, but I suspect that the CALL with doubled percents would work in NT4. – dbenham Jul 01 '14 at 17:01
1

I agree with AFH; you need to get CMD to “double-parse” the set statement.  But I’ve found a kludge for doing it that doesn’t involve a temporary batch file (or looking at every variable to find the one you want).  It uses a subroutine and a trick called delayed variable expansion.  Enable delayed expansion by adding

setlocal enabledelayedexpansion

somewhere near the beginning of your batch file.  The purpose of delayed variable expansion is somewhat complicated – see SET /? and SETLOCAL /? for more information – but the important thing to know is that it lets you reference variables with !variable_name! in addition to %variable_name%.

So here we go:

@echo off
setlocal enabledelayedexpansion
set var1=red
set var2=orange
set var3=yellow
set A=2
call :kludge var%A%
echo Newvar is %newvar%.
goto :eof

:kludge
set newvar=!%1!
exit /b

When we jump to :kludge, the statement is first transformed into set newvar=!var2! (because %1, the first argument to the subroutine, is var2) and then set newvar=orange (just as if the statement had been set newvar=%var2%).  So newvar gets set to orange.

BTW, goto :eof and exit /b are interchangeable.  If called from within a subroutine (i.e., someplace you got to with a call statement), they cause a return to the caller.  Otherwise, they act like a jump to the end of the batch file, causing the batch job to terminate without blowing away the parent, interactive, Command Prompt.

  • There is nothing kludgy about delayed expansion. It is an important feature of cmd.exe, and I find it to be a critical component to nearly all my intermediate or advanced batch scripts. There is no need for your :kludge routine. You can simply use set "newvar=!var%A%!", as I demonstrated in my answer. – dbenham Jul 03 '14 at 13:57
  • @dbenham: You took the words right out of my mouth – my answer is a kludge because it requires a subroutine to execute a single statement. – Scott - Слава Україні Jul 03 '14 at 14:12
  • 1
    I should temper my last comment a bit. Delayed expansion is no more or less kludgy than any other aspect of cmd.exe. Some might argue that the entire command processor is nothing but one massive kludge, and in some respects I would agree ;-) – dbenham Jul 03 '14 at 16:57