批处理文件中嵌套for循环的正确语法 [英] Correct syntax for nested for loops in batch file

查看:254
本文介绍了批处理文件中嵌套for循环的正确语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试查询许多服务器上已安装的应用程序的注册表值.我可以对服务器进行硬编码,并且有很多重复,而且似乎可以正常工作.但是有时服务器列表可能会更改,我想采用更明智的模块化方法.

I am trying to query the registry value of an installed application on many servers. I could hardcode the servers in, and have a lot of repetition and it seems to work. But sometimes a list of servers may change, and I'd like to take a more sensible modular approach.

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

So I can provide a test file with a list of server names, and then query the registry values of all of these servers, outputting them in a logfile.

我认为问题绝对是与我的循环/变量存储有关.不确定到底发生了什么,但是似乎一旦我获得了一组注册表值,它们就会为每台服务器输出,而不管它们各自的注册表值如何.

I think the issue is definitely with my loops/variable storing. Not sure exactly what is going on, but it seems like once I get one set of Registry values, these are outputted for every single server, regardless of their respective registry values.

不太有这种脚本编写经验,所以我一直通过反复试验将其混为一谈,以下是到目前为止的内容.请指出我犯的任何严重的语法错误.

Not too experience with this kind of scripting, so I have been sort of mashing this together through trial and error, below is what I have so far. Please point out any woeful syntax errors I've made.

因此从本质上讲,这是找到安装到每台服务器的McAfee扫描引擎版本. McAfee控制台本身的报告并不总是可靠的,我想检查一下内容是否已成功下拉到每台服务器.

So essentially this is to find a McAfee scan engine version installed to each server. The reporting from the McAfee console itself is not always reliable, and I want to check that the contents are successfully pulled down to each server.

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

There are two registry values required to create a full engine version, so I am required to pull both of these and then combine them into a single string.

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

At the moment I do get an output that looks correct, but it does not represent what is actually installed to each server. It is like one value is being picked up and then replicated.

另外要注意的是,这仅在命令行中执行时才起作用.并且运行的前1-2次没有任何值被拉高.感到我离解决方案还很遥远.

On an additional note, this only seems to work when executed in command line. And the first 1-2 times it is ran, no values are pulled up. Get the feeling I am quite far away from a solution.

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

为您能提供的任何帮助而欢呼.

Cheers for any help you can provide.

推荐答案

它与for语法无关,但是cmd是如何解析脚本的.请参阅 Windows命令解释程序(CMD.EXE)如何解析脚本?

It has nothing to do with for syntax, but how cmd parses scripts. See How does the Windows Command Interpreter (CMD.EXE) parse scripts?

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

When cmd parses a block (anything within parens), processes it as a single line. So it expands any %var% to its actual content. Changes made to it, are not taken into account until the block is exited. To retrieve new content within a block, you must enable delayed expansion, which forces the parser to evaluate it for every iteration. Also, syntax must be changed from %var% to !var!

在这里,由于您没有进行计算,因此从set命令中删除了/a开关,您可能会得到意料之外的结果(想象一个较小的版本,它等于0080,将被处理八进制(无效),并且会破坏脚本).另外,请注意用引号(set "minor=%%b")括起来的var名称和var内容,以避免不必要的尾随/前导空格.

Here, also, removed the /a switch from set command, as you are not doing calculations, and you may get results you won't expect (imagine a minor version equal to 0080 that will be treated as octal (invalid) and would break the script). Also, note both var name and var content enclosed in quotes (set "minor=%%b"), to avoid undesired trailing/leading spaces.

此外,我认为您不需要^| find /i "EngineVersion32Major部分,因为名为EngineVersion32Major的键可能只满足您所寻找的内容.再一次,将数据括在引号中(永远不知道什么时候可能出现空格).您也可以将"tokens=3"更改为"skip=1 tokens=3",以避免处理标题reg回声.

More also, I think you don't need the ^| find /i "EngineVersion32Major part, as possibly the key named EngineVersion32Major will content only what you are looking for. And again, enclose data in quotes (never know when a space may appear). You may also change "tokens=3" by "skip=1 tokens=3" to avoid process the heading reg echoes.

因此

@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

此外,无论是否启用延迟扩展(注意双百分号),此操作都在一个块内进行

Also, this works within a block regardless delayed expansion is enabled or not (note double percent sign)

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

另一个问题,每当在块中使用重定向时,系统都会打开和关闭文件(或流).

Another issue, any time a redirection is used within a block, the system opens and closes the file (or stream).

但是

@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

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

Processes all commands in the block, so the file is opened and closed only once. This may improve performance, specially with large files.

顺便说一句,

>>"%LOGFILE%" (
  ...
  ...
)

(
  ...
  ...
)>>"%LOGFILE%" 

这篇关于批处理文件中嵌套for循环的正确语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆