Reputation: 1770
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
?
Upvotes: 5
Views: 6280
Reputation: 9587
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?)
Upvotes: 8
Reputation: 439487
To complement the existing helpful answers with a more robust variant that also handles the following embedded characters correctly: & | < > ^
[1]
:
Note that for simplicity I'm using a string to drive the outer loop, whose literal value - to be expanded later by the inner loop - is %ProgramFiles%\Acme\FooBar %VersionNumber%
, due to the doubled %
instances.
set "VersionNumber=0.7"
for /f "delims=" %%f in ("%%ProgramFiles%%\Acme\FooBar %%VersionNumber%%") do (
for /f "delims=" %%g in ('echo "%%f"') do echo Folder: [%%~g]
)
This yields something like Folder: [C:\Program Files\Acme\FooBar 0.7]
Note:
for /f
interprets a single-quoted string ('...'
) as a command to execute and whose output to capture; delims=
tells for
to capture the output as a whole in a single variable.usebackq
with a `...`
-enclosed command instead, there's no advantage to doing so in this case.)Note how the reference to the outer loop's variable is double-quoted ("%%f"
), which is what allows the value to contain said special characters without breaking the echo
command.
Because the output will then also be double-quoted, the ~
operator is used to strip the enclosing double quotes from the captured value on echoing it (%%~g
).
[1] A solution that additionally handles embedded "
instances is trickier:
rem Construct a variable whose value contains all shell metacharacters.
rem % chars. meant to be treated as literals must be doubled (%%)
rem Note the extra " at the end, which appends an unbalanced double quote.
set "var=%%OS%% & %%ba^r | (baz) <mo'>""
rem Embedded " chars. must be escaped as "" (doubling them).
for /f "delims=" %%v in ('echo "%var:"=""%"') do set "expandedVar=%%~v"
rem Note: The resulting variable's value:
rem - can only be echoed *double-quoted*, as the command will otherwise break.
rem - still contains the *doubled* embedded double quotes, which, however,
rem is the escaping that other Microsoft programs expect.
echo "[%expandedVar%]"
This yields: "[Windows_NT & %ba^r | (baz) <mo'>""]"
Upvotes: 0
Reputation: 130899
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
)
Upvotes: 6