Windows批处理编程:间接/嵌套变量评估

时间:2012-02-20 23:14:47

标签: windows command-line batch-file

我们有一个列出一堆路径的文本文件,以及一个从该文件中读取行的批处理文件。

例如,TargetFolders.txt可能包含以下行:

%ProgramFiles%\Acme\FooBar %VersionNumber%

当然,当我们从文本文件中读取这一行时(使用FOR命令),变量%% I接收实际行文本,使用%符号而不是替换变量值。所以,

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

打印

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

如何使其替换实际变量值,以便打印

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

3 个答案:

答案 0 :(得分:8)

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
)

你去吧。 (这就是你想要的,对吗?)

答案 1 :(得分:5)

简单地添加CALL可以解决您的问题。 (也是你对VersionNumber的定义错了)

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

但如果您的文件包含&><|等不带引号的特殊字符,则会失败。

例如,以下行将失败:

%ProgramFiles%\This&That\ %VersionNumber%

如果引用它将起作用

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

CALL也会破坏任何引用的插入符号:"^"将成为"^^"

最佳解决方案是修改您的文本文件,并将每个%替换为!

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

现在,您可以安全地使用延迟扩展来扩展循环中的变量。

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

如果您的文本文件已经保留了!,则必须对其进行转义。如果^显示在带有!的行上,则必须对preserve caret ^^ and exclamation ^! by escaping caret ^ without exclamation is no problem 进行转义。

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

或者,您可以将变量替换为插入符号和感叹号文字

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

然后在批处理中定义变量

{{1}}

答案 2 :(得分:0)

使用更健壮的变体补充现有的有用答案,也正确处理以下嵌入字符:& | < > ^ [1]

请注意,为简单起见,我使用字符串来驱动外部循环,其文字值 - 来之后由内循环扩展 - %ProgramFiles%\Acme\FooBar %VersionNumber%,因为%实例加倍。

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]
)

这会产生类似Folder: [C:\Program Files\Acme\FooBar 0.7]

的内容

注意:

  • 默认情况下,for /f单引号字符串('...')解释为要执行的命令和要捕获的输出; delims=告诉for将输出作为一个整体捕获到单个变量中 (虽然可以使用usebackq并使用`...`封闭的命令,但在这种情况下这样做没有任何优势。)
  • 注意外部循环变量的引用是如何双引号"%%f"),这是允许值包含所述特殊字符的原因打破echo命令。

  • 因为输出也会被双引号,~运算符用于在回显它(%%~g)时从捕获的值中去除封闭的双引号。

[1]另外处理嵌入式"实例的解决方案比较棘手:

  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%]"

这会产生:"[Windows_NT & %ba^r | (baz) <mo'>""]"