首先,打开命令提示符窗口,运行set /? 并在几页上阅读命令SET 的完整帮助输出。它在 IF 和 FOR 示例中解释了 delayed expansion 的用法。
阅读答案很可能也有帮助:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
您的批处理文件在顶部包含setlocal enabledelayedexpansion,以启用延迟的环境变量扩展。但是没有使用语法!VariableName! 引用环境变量来真正利用延迟的环境变量扩展。出于这个原因,"%Element%" 已被 Windows 命令处理器修改,它在解析以 ( 开头并以匹配 ) 结束的整个命令块到仅 "" 之前执行命令 FOR。环境变量 Element 在到达 FOR 命令行之前未定义,cmd.exe 解析整个 FOR 命令行,命令块以 ) 结尾执行FOR之前的批处理文件。
CALL 主要用于从一个批处理文件中调用一个子程序或另一个批处理文件。在简单的命令行上使用 CALL 可用于获取由 Windows 命令处理器解析两次的命令行,以避免使用延迟扩展。在前三个 SET 行中,绝对没有必要使用 CALL,因为第二次解析 SET 命令行时没有任何变化。 p>
第一个解决方案是不使用延迟扩展,使用 CALL 双重解析代码块中的两个命令行。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do (
call set "Element=%%ListOFElts[%%I]%%"
call %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "%%Element%%"
)
endlocal
环境变量Element的定义在命令块中是不必要的,因为它的值只被引用一次。更紧凑,因此执行速度更快的是:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do call %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "%%ListOFElts[%%I]%%"
endlocal
FOR 在每次循环迭代时不再需要执行命令块,只有一个命令行。但仍然需要使用命令 CALL 并使用 %%ListOFElts[%%I]%%,因为在执行 FOR 之前已经为 %VariableName% 引用解析了整个 FOR 命令行强>第一次。所以在 FOR 执行之前,"%ListOFElts[%%I]%" 已经被替换为 ""。
第三种解决方案是真正使用延迟扩展。
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do (
set "Element=!ListOFElts[%%I]!"
%SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "!Element!"
)
第四个解决方案是使用延迟扩展的紧凑版本,类似于 FOR 命令输出的示例 SET:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "!ListOFElts[%%I]!"
endlocal
FINDSTR 命令可以指定多个搜索字符串。
@%SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\findstr.exe /L /C:"First" /C:"Second" /C:"Third"
FINDSTR 输出输入流中包含/C:"..." 指定的三个字面和区分大小写的解释字符串中的任何一个的所有行。批处理文件中的这个单一命令行替换了上述所有四个批处理文件。
要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
call /?
echo /?
endlocal /?
find /?
findstr /?
for /?
set /?
setlocal /?
whoami /?
另请参阅Why is no string output with 'echo %var%' after using 'set var = text' on command line? 上的答案以详细解释为什么在所有 SET 命令行上使用"variable=value" 而不是在上面的批处理文件中仅使用variable=value。