Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 748 Vote(s) - 3.43 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Windows batch programming: Indirect/nested variable evaluation

#1
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

?
Reply

#2
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
)
Reply

#3
To complement the existing helpful answers with a **more robust variant** that also **handles the following embedded characters correctly: `& | < > ^`**<sup>[1]</sup>
:

<sup>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.</sup>

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:

* By default, `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.
(While you _can_ use `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'>""]"`
Reply

#4
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?)
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through