Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows batch programming: Indirect/nested variable evaluation

We have a text file that lists a bunch of paths, and a batch file that reads the lines from this file.

For instance, TargetFolders.txt might contain the line:

%ProgramFiles%\Acme\FooBar %VersionNumber%

Naturally, when we read this line from the text file (using a FOR command), the variable %%I receives the actual line text, with the % signs rather than replacing the variable values. So,

SET VersionNumber=7.0
FOR /F "eol=; delims=" %%I IN (TargetFolders.txt) DO (
    echo Folder: %%I
)

Prints

Folder: %ProgramFiles%\Acme\FooBar %VersionNumber%

How does one make it replace the actual variable values, so that it prints

Folder: C:\Program Files\Acme\FooBar 7.0

?

like image 388
System.Cats.Lol Avatar asked Feb 20 '12 23:02

System.Cats.Lol


2 Answers

SET VersionNumber=7.0
FOR /F "eol=; delims=" %%I IN (TargetFolders.txt) DO (
    for /F "usebackq delims=" %%J in (`echo %%I`) do echo Folder: %%J
)

There you go. (This is what you wanted, right?)

like image 144
Irfy Avatar answered Sep 28 '22 07:09

Irfy


Simply adding a CALL may solve your problem. (also your definition of VersionNumber was wrong)

SET VersionNumber=7.0
FOR /F "eol=; delims=" %%I IN (TargetFolders.txt) DO (
  call echo Folder: %%I
)

But this will fail if your file contains unquoted special characters like &, >, <, |.

For example, the following line would fail:

%ProgramFiles%\This&That\ %VersionNumber%

It will work if it is quoted

"%ProgramFiles%\This&That\" %VersionNumber%

The CALL will also mangle any quoted carets: "^" will become "^^"

The best solution would be to modify your text file and replace each % with !.

!ProgramFiles!\Acme\FooBar !VersionNumber!
!ProgramFiles!\This&That !VersionNumber!

Now you can safely use delayed expansion to expand the variables within the loop.

setlocal enableDelayedExpansion
SET VersionNumber=7.0
FOR /F "eol=; delims=" %%I IN (TargetFolders.txt) DO (
  echo Folder: %%I
)

If your text file already has ! that you want to preserve, then it must be escaped. Also ^ will have to be escaped if it appears on a line with a !.

preserve caret ^^ and exclamation ^! by escaping
caret ^ without exclamation is no problem

Alternatively you can substitute variables for caret and exclamation literals

alternate method to preserve caret !c! and exclamation !x!
caret ^ without exclamation still no problem

And then define the variables in your batch

setlocal enableDelayedExpansion
set "x=^!"
set "c=^"
SET VersionNumber=7.0
FOR /F "eol=; delims=" %%I IN (TargetFolders.txt) DO (
  echo Folder: %%I
)
like image 25
dbenham Avatar answered Sep 28 '22 06:09

dbenham