为什么在处理WMIC输出并将值分配给变量时输出错误消息“缺少操作数”?

时间:2018-11-29 19:17:06

标签: batch-file cmd wmic

我正在处理一个批处理文件,该文件应显示当前估计的剩余费用。但是当我运行命令时,我得到了期望的结果以及错误消息Missing operand.的输出。

我的代码:

FOR /F "delims= skip=1" %%i IN ('WMIC PATH Win32_Battery Get EstimatedChargeRemaining') DO (SET /a CHR=%%i)
ECHO "Battery Level: %CHR%"

如何摆脱不需要的输出Missing operand.

我已经尝试从最后一部分(即%)中删除DO (SET /a CHR=i),但是当我这样做时,我最终得到的是"Battery Level: 0",好像它跳过了其中的一些数字一样。结果。

2 个答案:

答案 0 :(得分:4)

Windows Management Instrumentation Command-line实用程序输出文本UTF-16byte order mark(BOM)编码的Little Endian,这意味着(几乎)每个字符总是两个字节,而没有显示FF FE(BOM输出文本开头的十六进制字节。

FOR 设计用于使用ASCII / ANSI / OEM编码来解析文本,这些编码为character encodings,每个字符仅使用一个字节。通过在命令提示符窗口中运行命令chcp来输出使用的代码页,该命令确定哪个字符由一个字节表示,其值的范围从十进制0255或十六进制00FF。默认情况下,Windows命令行环境中使用的代码页取决于为使用的用户帐户设置的区域/国家/地区。

让我们看看发布的代码:

FOR /F "delims= skip=1" %%i IN ('WMIC PATH Win32_Battery Get EstimatedChargeRemaining') DO (SET /a CHR=%%i)
ECHO "Battery Level: %CHR%"

例如,wmic的输出中,表示Windows 7和Windows XP上的回车+换行符:

EstimatedChargeRemaining  ¶
93                        ¶

此输出重定向到文件中并以十六进制查看,如下所示:

0000h: FF FE 45 00 73 00 74 00 69 00 6D 00 61 00 74 00 ; ÿþE.s.t.i.m.a.t.
0010h: 65 00 64 00 43 00 68 00 61 00 72 00 67 00 65 00 ; e.d.C.h.a.r.g.e.
0020h: 52 00 65 00 6D 00 61 00 69 00 6E 00 69 00 6E 00 ; R.e.m.a.i.n.i.n.
0030h: 67 00 20 00 20 00 0D 00 0A 00 39 00 33 00 20 00 ; g. . .....9.3. .
0040h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ;  . . . . . . . .
0050h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00 ;  . . . . . . . .
0060h: 20 00 20 00 20 00 20 00 20 00 20 00 20 00 0D 00 ;  . . . . . . ...
0070h: 0A 00                                           ; ..

格式为:十六进制偏移量:十六进制字节; Windows-1252字符表示形式

上面的代码导致在单独的命令过程中跳过wmic输出的第一行,该命令过程由 FOR 使用cmd.exe /C通过使用环境变量ComSpec FOR 捕获,仅显示值名称EstimatedChargeRemaining

第二行包含感兴趣的值,该值包含一个,两位或三位数字,取决于该值的数字,它们之间有21到23个空格,首先分配给循环变量i,然后分配给环境变量CHR使用算术表达式忽略尾随空格。

根据Stephan对您先前的问题How to get value without unwanted spaces in WMIC results?的评论编写的这段代码在Windows XP上可以完美运行,但在Windows 7上会出现错误消息:

  

缺少操作数。

在Windows XP上,只有一个循环迭代,即为值93分配22个尾随空格,并将回车符返回到环境变量CHR,其中空格和回车符被命令< strong> SET (由于算术表达式)。

但是在Windows 7上,第二次运行循环,只是将回车分配给了循环变量i。在算术表达式的求值时,命令 SET 忽略了垂直空格字符回车,该结果导致在第二个循环迭代set /a CHR=上执行,因此确实缺少等号后的操作数语法正确的算术表达式。

此问题 FOR 在解析UTF-16编码输出时有多种解决方案。

一个很简单的方法是在将感兴趣的值分配给环境变量后退出 FOR 循环。

for /F "skip=1" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_Battery GET EstimatedChargeRemaining') do set "CHR=%%I" & goto HaveValue
:HaveValue
echo Battery level: %CHR%%%

因此, FOR 循环仅迭代一次,并且仅处理wmic输出的第二行,其中包含感兴趣的值和尾随空格。选项delims=用于定义一个空的定界符列表,用于获取 FOR 已处理从{{ 1}},因此循环变量wmic已经拥有感兴趣的值,没有尾随空格。这样就可以省略 SET 参数I,而无需使用算术表达式即可将值仅分配给环境变量。

解决由 FOR 输出的/A的UTF-16编码行尾错误解析而解决此问题的另一种简单解决方案,是使用如下代码:

wmic

例如,带有选项for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_Battery GET EstimatedChargeRemaining /VALUE') do set "CHR=%%I" echo Battery level: %CHR%%% 的{​​{1}}的输出是wmic代表回车+换行符:

/VALUE

此输出重定向到文件中并以十六进制查看,如下所示:

因此开头有两个空行,即使使用UTF-16编码,它们也总是被 FOR 忽略。然后是包含值名称和值之间带有等号的行。最后还有两个空行。

这两个 FOR 选项¶ ¶ EstimatedChargeRemaining=93¶ ¶ ¶ 导致第三行在等号处分割,仅在等号后将第二个字符串分配给循环变量{{1} },该变量仅在环境变量0000h: FF FE 0D 00 0A 00 0D 00 0A 00 45 00 73 00 74 00 ; ÿþ........E.s.t. 0010h: 69 00 6D 00 61 00 74 00 65 00 64 00 43 00 68 00 ; i.m.a.t.e.d.C.h. 0020h: 61 00 72 00 67 00 65 00 52 00 65 00 6D 00 61 00 ; a.r.g.e.R.e.m.a. 0030h: 69 00 6E 00 69 00 6E 00 67 00 3D 00 39 00 33 00 ; i.n.i.n.g.=.9.3. 0040h: 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; ............ 旁边分配。由于在tokens=2 delims==输出末尾解析的空行错误,命令 SET 仅执行一次,结果仅在一个子字符串中被 FOR 找到回车符由于没有第二个子字符串,因此它无法为循环变量I分配任何内容。因此, FOR 不会第二次执行命令 SET

npocmakaanswer on your previous question的形式发布了另一种简单的解决方案,方法是使用第二个 FOR 循环来处理感兴趣的值正确的行。

其他解决方案使用附加文件或附加命令将UTF-16编码的文本输出为ASCII编码的文本, FOR 可以捕获和处理这些文本而没有任何问题。有关此类解决方案,请参见How to correct variable overwriting misbehavior when parsing output?上的答案。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • CHR
  • wmic
  • I
  • echo /?
  • for /?
  • goto /?
  • set /?
  • wmic /?

答案 1 :(得分:3)

之所以发生这种情况,是因为WMIC输出中的100之后有行。 WMIC为我输出4条线。它将跳过第一行,然后继续其他行,其中只有一条有效。

@echo off
FOR /F "delims= skip=1" %%i IN ('WMIC PATH Win32_Battery Get EstimatedChargeRemaining') DO (
    SET /a CHR=%%i
    goto loopdone
)
:loopdone
ECHO "Battery Level: %CHR%"