修正批处理文件中嵌套for循环的语法

时间:2017-06-09 10:42:00

标签: batch-file cmd registry

我正在尝试在许多服务器上查询已安装应用程序的注册表值。我可以硬编码服务器,并有很多重复,它似乎工作。但有时服务器列表可能会发生变化,我想采用更合理的模块化方法。

所以我可以提供一个包含服务器名称列表的测试文件,然后查询所有这些服务器的注册表值,并将它们输出到日志文件中。

我认为问题肯定在于我的循环/变量存储。不确定到底发生了什么,但似乎一旦我得到一组注册表值,就会为每个服务器输出这些值,而不管它们各自的注册表值。

对这种脚本没有太多经验,所以我通过反复尝试将它们混合在一起,下面是我到目前为止所做的。请指出我所犯的任何可怕的语法错误。

基本上,这是为每台服务器安装一个McAfee扫描引擎版本。来自McAfee控制台本身的报告并不总是可靠的,我想检查内容是否已成功下载到每个服务器。

创建完整引擎版本需要两个注册表值,因此我需要同时提取这两个值,然后将它们组合成一个字符串。

目前我确实得到了一个看起来正确的输出,但它并不代表实际安装到每个服务器的内容。就像一个值被拾取然后被复制。

另外请注意,这只在命令行中执行时才有效。并且运行前1-2次,没有值被提升。感觉我离解决方案很远。

SET LOGFILE=C:\LogFile.log
For /f %%i in (servers.txt) DO (
for /f "tokens=3" %%a in ('reg query \\%%i\HKLM\SOFTWARE\McAfee\AVEngine /v EngineVersion32Major ^| find /i "EngineVersion32Major"') do set /a major=%%a
for /f "tokens=3" %%b in ('reg query \\%%i\HKLM\SOFTWARE\McAfee\AVEngine /v EngineVersion32Minor ^| find /i "EngineVersion32Minor"') do set /a minor=%%b
echo %%i: %major%.%minor% >> %LOGFILE%
)

期望这样的输出:

server1 : 5900.5647
server2 : 6000.4589
server3 : 5900.5647
server4 : 5900.5647

欢呼您提供任何帮助。

2 个答案:

答案 0 :(得分:2)

它与for语法无关,但cmd如何解析脚本。见How does the Windows Command Interpreter (CMD.EXE) parse scripts?

cmd解析一个块(parens中的任何内容)时,将其作为一行进行处理。因此,它将任何%var%扩展为其实际内容。在退出块之前,不会考虑对其所做的更改。要检索块中的新内容,必须启用delayed expansion,这会强制解析器在每次迭代时对其进行评估。此外,语法必须从%var%更改为!var!

此处,还从/a命令中移除了set开关,因为您没有进行计算,并且您可能会得到您不会期望的结果(想象一下等于{的次要版本{1}}将被视为八进制(无效)并将破坏脚本)。另外,请注意用引号(0080)括起的var name和var内容,以避免不需要的尾随/前导空格。

此外,我认为您不需要set "minor=%%b"部分,因为名为^| find /i "EngineVersion32Major的密钥可能只会满足您的要求。再次,将数据括在引号中(永远不知道何时可能出现空格)。您也可以按EngineVersion32Major更改"tokens=3",以避免处理标题"skip=1 tokens=3"回音。

因此

reg

此外,无论是否启用延迟扩展,这都适用于块(注意双百分号)

@echo off
SetLocal EnableDelayedExpansion
SET LOGFILE=C:\LogFile.log
for /f %%i in (servers.txt) DO (
  for /f "tokens=3" %%a in ('reg query "\\%%i\HKLM\SOFTWARE\McAfee\AVEngine" /v "EngineVersion32Major"') do set "major=%%a"
  for /f "tokens=3" %%b in ('reg query "\\%%i\HKLM\SOFTWARE\McAfee\AVEngine" /v "EngineVersion32Minor"') do set "minor=%%b"
  echo %%i: !major!.!minor!>>%LOGFILE%
)
EndLocal

另一个问题是,无论何时在块内使用重定向,系统都会打开并关闭文件(或流)。

但是

call echo %%i: %%major%%.%%minor%%>>%LOGFILE%

处理块中的所有命令,因此文件只打开和关闭一次。这可以提高性能,特别是对于大文件。

BTW,

@echo off
SetLocal EnableDelayedExpansion
SET LOGFILE=C:\LogFile.log
>>"%LOGFILE%" (
  for /f %%i in (servers.txt) DO (
    for /f "tokens=3" %%a in ('reg query "\\%%i\HKLM\SOFTWARE\McAfee\AVEngine" /v "EngineVersion32Major"') do set "major=%%a"
    for /f "tokens=3" %%b in ('reg query "\\%%i\HKLM\SOFTWARE\McAfee\AVEngine" /v "EngineVersion32Minor"') do set "minor=%%b"
    echo %%i: !major!.!minor!
  )
)
EndLocal

相同
>>"%LOGFILE%" (
  ...
  ...
)

答案 1 :(得分:0)

请使用search工具在delayed expansion上找到许多SO文章。

您的案例中的简单方法是使用

call echo %%i: %%major%%.%%minor%% >> %LOGFILE%