【问题标题】:For /F with wmic unwanted output对于带有 wmic 不需要的输出的 /F
【发布时间】:2016-01-08 19:35:40
【问题描述】:

这里是第一次发帖,如果我做得不对,请见谅。

我正在尝试在远程 Windows PC 上输出操作系统版本,但我不断收到不需要的数据。执行这个批处理文件:

@echo off
set /p hostname=PC hostname?
echo.
FOR /F "skip=1 tokens=*" %%A in ('wmic /node:%hostname% OS get caption') DO echo %%A
echo.
pause

返回这个结果:

Microsoft Windows 7 Professional
Echo is off.

我能够使用skip=1 删除Caption 输出,但我不明白echo 命令的来源。拆分命令没有帮助,但是打开 echo 表明,显然,循环的 wmic 命令在输出操作系统版本后输出echo,所以,很明显,当 echo 关闭时,我得到最终输出:@987654327 @。谁能帮我理解为什么会出现echo 输出?

【问题讨论】:

  • 我可以告诉你为什么会这样,但不能告诉你如何阻止它。如果从命令提示符运行 wmic 输出是三行:CaptionMicrosoft Windows 7 Professional 和一个空行。空行导致 %%A 在第三次调用 DO echo %%A 时为空,这导致只执行 echo,这导致输出 ECHO 的当前状态(Echo is off i>)。

标签: batch-file echo wmic


【解决方案1】:

Magoo 确定了问题的根源 - WMIC unicode 输出到 ANSI 的转换存在缺陷,因为每一行都以 CRCRLF结尾> 而不是普通的 CRLF

FOR /F 在每个 LF 处中断(并剥离),留下 CRCR。 FOR /F 当且仅当它恰好是 CR 时,从每一行中删除最后一个字符,以便在每一行的末尾留下一个 CR。 FOR /F 忽略空行,但 CR 不是空行,因此不需要的 Echo is off. 输出。

Magoo 和 Squashman 为您的问题提供了可行的解决方案,但它们并不是适用于所有 FOR /F - WMIC 情况的通用解决方案。当 FOR /F 输出存储在变量中时会出现一个常见问题 - 不需要的 CR 通常位于值的末尾,这可能会导致以后出现问题。

我们可以使用 FOR /F 的已知机制,通过简单地添加一个额外的 FOR /F,从每一行中去除不需要的 CR

所以总是有效的通用模板看起来像

for delims^=^ eol^= %%. in ('wmic ....') do for /f "whatever options you need" %%A in ("%%.") do ...

或者如果你需要跳过N行,那么

for skip^=N^ delims^=^ eol^= %%. in ('wmic ....') do for /f "whatever options you need" %%A in ("%%.") do ...

第一个 FOR /F 中的神秘语法将 DELIMS 和 EOL 都设置为空。如果您知道您的输出中没有一个以; 开头,那么您可以简单地使用"delims=""skip=N delims="。你的情况就是这样。

所以解决方案变成:

for /f "skip=1 delims=" %%. in ('wmic /node:%hostname% OS get caption') do for /f "delims=" %%A in ("%%.") do echo %%A

【讨论】:

  • 在cmd中直接输入wmic datafile where name="C:\\file.exe" get Version这个命令会怎样?
【解决方案2】:

将它传递给 find 命令。

@echo off
set /p hostname=PC hostname?
echo.
FOR /F "tokens=1,2 delims==" %%A in ('wmic /node:%hostname% OS get caption /value ^|find /I "caption"') DO echo %%B
echo.
pause

【讨论】:

  • 对不起,如果我的帖子令人困惑。我只想要实际的操作系统名称。我已经过滤掉了“标题”标题,所以我绝对不想找到它。我需要的是循环的最后一次迭代,这是一个空行,消失。 Ken White 在上面指出,这就是导致不需要的echo is off 的原因。我需要把那部分拿出来。
  • @MattD,我最初是在测试/value,然后把它拿出来。代码已更新。现在应该按照您想要的方式工作。
【解决方案3】:

我建议

set "remotever="
FOR /F "skip=1 tokens=*" %%A in ('wmic /node:%hostname% OS get caption^|more') DO if not defined remotever set "remotever=%%A"
echo %remotever:~0,-1%

more 是将wmic 的 unicode 输出转换为 ANSI 的经典批处理方法。

但是有一个问题。除了 Unicode,WMICCRCRLF 而不是 CRLF “结束”它的行 并且倒数第二个 CR 然后 included 在分配给变量的值中(因此 echo 子字符串不包括最后一个字符 - 你会发现一些尾随空格...)。

(作为一个稍微简单的演示,在您的原始版本中尝试echo q%%Aj - 您会发现qj 覆盖)

因此,要捕获第一行,set 将变量设置为 nothing,然后在 for 循环中将 set 它设置为您要捕获的值,但将 @ 987654332@ 和if not defined

【讨论】:

  • 将 WMIC 放入 FOR /F 会自行将输出转换为 ANSI - 不需要更多。无论哪种方式,CR CR LF 问题仍然存在。
  • 正如@dbenham 提到的,不需要more.com。 wmic.exe 对管道和控制台使用有损 OEM 编码进行硬编码(控制台不是 Unicode,甚至不是当前控制台代码页,这没有意义),磁盘文件使用 UTF-16 Unicode。由于for /f 使用控制台的当前代码页进行解码,为避免 mojibake,您需要首先运行 chcp.com [oemcp] 以确保控制台使用的是 OEM 代码页,无论当前区域设置如何。
【解决方案4】:
@echo off
for /f "usebackq delims= skip=1" %%a in (`wmic OS get caption 2^>nul ^| findstr "."`) do set caption=%%a
for /f "usebackq delims=" %%a in (`echo %caption%`) do set caption=%%a
set "caption=%caption:~0,-1%"
echo Caption=[%caption%]

【讨论】:

  • 虽然您所写的内容可能会回答这个问题,但它似乎确实有点缺乏解释,并且可能会给其他用户造成非法混淆。您能否扩展您的答案,使其更清晰、更易于理解?这将提供更好的答案,并帮助未来的用户了解问题是如何解决的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多