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

我们有一个列出一堆path的文本文件,以及一个从这个文件中读取行的batch file

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

%ProgramFiles%\Acme\FooBar %VersionNumber% 

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

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

打印

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

如何使其取代实际的variables值,以便打印

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

 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 ) 

你走了 (这是你想要的,对吧?)

只需添加一个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]

请注意,为了简单起见,我使用了一个字符串来驱动外部循环,由于内部循环后面的内部循环扩展了%实例,所以它是%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=通过一个变量来捕获整个输出。
    (虽然你可以使用usebackq来代替`...` -enclosed命令,但在这种情况下这样做没有任何优势。)
  • 注意对外循环变量的引用是如何用双引号"%%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'>""]"