【问题标题】:How to get the Percentage of memory utilization using WMIC in batch script?如何在批处理脚本中使用 WMIC 获取内存利用率百分比?
【发布时间】:2021-05-12 21:11:57
【问题描述】:

我没有得到仅使用 W MIC 的批处理脚本中内存利用率百分比的结果。我只得到总内存和可用内存(以字节为单位)。

那么如何获得以兆字节为单位的那些以及如何计算内存利用率的百分比?

代码:-

@echo off
setlocal enabledelayedexpansion

set Times=0
for /f "skip=1" %%p in ('wmic cpu get loadpercentage') do (
    set Cpusage!Times!=%%p
    set /A Times+=1
)

echo CPU Percentage = %Cpusage0%%%

set Times=0
for /f "skip=1" %%p in ('wmic ComputerSystem get TotalPhysicalMemory') do (
    set totalMem!Times!=%%p
    set /A Times+=1
)

set Times=0
for /f "skip=1" %%p in ('wmic OS get FreePhysicalMemory') do (
    set availableMem!Times!=%%p
    set /A Times+=1
)

set Times=0
for /f "skip=1" %%p in ('wmic OS get FreePhysicalMemory ^|findstr physical') do (
    set /a UsedMem= totalMem - availableMem
    set usedMem!Times!=%%p
    set /A Times+=1
)
set /a usedpercent=(usedMem*100)/totalMem

echo Free MEMORY = %availableMem0% Bytes
echo Total MEMORY = %totalMem0% Bytes
echo Used MEMORY = %UsedMem0% Bytes
echo Memory Utilization = %usedpercent0%%%

pause

【问题讨论】:

  • 这个任务在cmd恐怕是无解了。下一个命令 for /f "skip=1" %G in ('wmic ComputerSystem get TotalPhysicalMemory') do @for %g in (%G) do set /a %g 返回 Invalid number. Numbers are limited to 32-bits of precision。切换到 PowerShell。
  • 我已经添加了一个关于相同的代码(代码号 2),请查看并帮助完成。我需要类似的输出:- 总内存:8105 MB 已用内存:3760 MB 可用内存:4345 MB 内存使用率 = 46% CPU 使用率 = 2%,我已经通过使用系统信息实现了这个输出,但我需要在 WMIC 中同样的输出。请帮忙

标签: windows batch-file scripting


【解决方案1】:

如果没有必要多次使用setlocal,则setlocal enabledelayedexpansion 通常只在批处理文件中使用一次。此命令不仅启用延迟扩展模式。它总是还复制整个当前环境表(最大可达 64 MB)、命令扩展和延迟扩展的当前状态以及堆栈(内存)上的当前目录路径。这种环境推送到堆栈的数量不是无限的。至少在两者之间使用endlocal 以避免由于堆栈溢出而提前退出批处理。有关更多详细信息,请参阅以下答案:

即使是 64 位 Windows 命令处理器 (cmd.exe) 也使用 32 位有符号整数。因此,取值范围限制在 -2.147.483.648 到 +2.147.483.647。换句话说,如果整数溢出产生错误结果,就无法完成 2 GB 或更多的算术运算。

这是一个注释批处理文件,它不适用于所有可能的已安装 RAM 配置,但适用于 2016 年的典型配置:2 GB、4 GB、8 GB、16 GB 和 32 GB。

@echo off

rem Note: KB = KiB, MB = MiB and GB = GiB in this batch file, see
rem       https://en.wikipedia.org/wiki/Byte for details on GiB.

rem Create a copy of current environment variables. Enabling additionally
rem delayed environment variable expansion is not required for this task.
setlocal EnableExtensions DisableDelayedExpansion

rem The command WMIC with the parameters CPU GET LoadPercentage outputs
rem one line per processor. The output of WMIC is in UTF-16 LE with BOM.
rem The output is redirected to a temporary file which is printed by
rem command TYPE to STDOUT which makes a better job on UNICODE to ASCII
rem conversion as command FOR. Note: 1 processor can have 1 or more cores.

set "CpuUsage=0"
set "Processors=0"
%SystemRoot%\System32\wbem\wmic.exe CPU GET LoadPercentage >"%TEMP%\cpu_usage.tmp"
for /F "skip=1" %%P in ('type "%TEMP%\cpu_usage.tmp"') do (
    set /A CpuUsage+=%%P
    set /A Processors+=1
)
del "%TEMP%\cpu_usage.tmp"

rem Calculate the CPU usage as percentage value of all processors.
set /A CpuUsage/=Processors
goto GetTotalMemory

rem Output of WMIC is in UTF-16 LE with BOM. The interpretation of this
rem output in ASCII/OEM can result in processing three lines instead of
rem just two with third line being just a carriage return. Therefore exit
rem each loop after assigning the value of second line to the variable.

:GetTotalMemory
for /F "skip=1" %%M in ('%SystemRoot%\System32\wbem\wmic.exe ComputerSystem GET TotalPhysicalMemory') do set "TotalMemory=%%M" & goto GetAvailableMemory
:GetAvailableMemory
for /F "skip=1" %%M in ('%SystemRoot%\System32\wbem\wmic.exe OS GET FreePhysicalMemory') do set "AvailableMemory=%%M" & goto ProcessValues

rem Total physical memory is in bytes which can be greater 2^31 (= 2 GB)
rem Windows command processor performs arithmetic operations always with
rem 32-bit signed integer. Therefore 2 GB or more installed physical
rem memory exceeds the bit width of a 32-bit signed integer and arithmetic
rem calculations are wrong on 2 GB or more installed memory. To avoid
rem the integer overflow, the last 6 characters are removed from bytes
rem value and the remaining characters are divided by 1073 to get the
rem number of GB. This workaround works only for physical RAM being
rem an exact multiple of 1 GB, i.e. for 1 GB, 2 GB, 4 GB, 8 GB, ...

rem  1 GB =  1.073.741.824 bytes = 2^30
rem  2 GB =  2.147.483.648 bytes = 2^31
rem  4 GB =  4.294.967.296 bytes = 2^32
rem  8 GB =  8.589.934.592 bytes = 2^33
rem 16 GB = 17.179.869.184 bytes = 2^34
rem 32 GB = 34.359.738.368 bytes = 2^35

rem But there is one more problem at least on Windows XP x86. About 50 MB
rem of RAM is subtracted as used by Windows itself. This can be seen in
rem system settings when 1.95 GB is displayed although 2 GB is installed.
rem Therefore add 50 MB before dividing by 1073.

:ProcessValues
set "TotalMemory=%TotalMemory:~0,-6%"
set /A TotalMemory+=50
set /A TotalMemory/=1073

rem The total memory in GB must be multiplied by 1024 to get the
rem total physical memory in MB which is always small enough to
rem be calculated with a 32-bit signed integer.

set /A TotalMemory*=1024

rem The available memory is in KB and therefore there is
rem no problem with value range of 32-bit signed integer.

set /A AvailableMemory/=1024

rem So the used memory in MB can be determined easily.

set /A UsedMemory=TotalMemory - AvailableMemory

rem It is necessary to calculate the percentage value in MB instead of
rem KB to avoid a 32-bit signed integer overflow on 32 GB RAM and nearly
rem entire RAM is available because used is just a small amount of RAM.

set /A UsedPercent=(UsedMemory * 100) / TotalMemory

if "%Processors%" == "1" (
    set "ProcessorInfo="
) else (
    set "ProcessorInfo= of %Processors% processors"
)
echo CPU percentage: %CpuUsage% %%%ProcessorInfo%
echo Free memory:    %AvailableMemory% MB
echo Total memory:   %TotalMemory% MB
echo Used memory:    %UsedMemory% MB
echo Memory usage:   %UsedPercent% %%

rem Discard the current environment variable table and restore previous
rem environment variables. The states of command processor extension
rem (default: ON) and delayed expansion (default: OFF) as well as the
rem original current directory are restored by this command although
rem not modified at all by the commands above.
endlocal

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

  • del /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • rem /?
  • setlocal /?
  • set /?
  • type /?
  • wmic /?
  • wmic CPU get /?
  • wmic OS get /?
  • wmic ComputerSystem get /?

【讨论】:

    【解决方案2】:

    Win32_ComputerSystem class 的TotalPhysicalMemory 属性(以字节为单位,uint64 数据类型)超出了set /A 批处理文件整数算术限制(请参阅set command):限制为 32 位精度(对应于 uint32 数据类型)即 cca ±2 gibibytes (GiB).

    让我们从位于mebibytes (MiB) 的Systeminfo command 捕获输出:

    ==> systeminfo | find /I "Physical Memory"
    
    Total Physical Memory:     8 137 MB
    Available Physical Memory: 4 210 MB
    
    ==>
    

    因此set /A 就足够了:32 位限制已不堪重负。

    remcmets 中的解释:

    @ECHO OFF >NUL
    SETLOCAL EnableExtensions
    echo(---
    set "_memo_total="
        rem unfortunately, next command is (supposedly) locale dependent
    for /F "tokens=1,* delims=:" %%G in ('
            systeminfo^|find /I "Physical Memory"
                                        ') do (
      set "_memo_inuse="
          rem remove spaces including no-break spaces
      for %%g in (%%H) do if /I NOT "%%g"=="MB" set "_memo_inuse=!_memo_inuse!%%g"
      if defined _memo_total ( set "_memo_avail=!_memo_inuse!" 
                      ) else ( set "_memo_total=!_memo_inuse!" )
      echo !_memo_inuse! [MB] %%G 
    )
    set /A "_memo_inuse=_memo_total - _memo_avail"
        rem in integer arithmetics: calculate percentage multipled by 100 
    set /A "_perc_inuse=10000 * _memo_inuse / _memo_total"
    set /A "_perc_avail=10000 * _memo_avail / _memo_total"
        rem debugging: mostly 9999 as `set /A` trucates quotients instead of rounding  
    set /A "_perc__suma=_perc_inuse + _perc_avail
    echo(---
    call :formatpercent _perc_avail
    call :formatpercent _perc_inuse
    call :formatpercent _perc__suma
        rem display results
    set _
    ENDLOCAL
    goto :eof
    
    :formatpercent
        rem         simulates division by 100
    
        rem input : variable NAME (i.e. passed by reference)
        rem         it's value could vary from   0 to 10000   format mask ####0  
        rem output: variable VALUE 
        rem             respectively vary from .00 to 100.00  format mask ###.00
    if NOT defined %1 goto :eof
    SETLOCAL EnableDelayedExpansion
      set "aux5=     !%1!"
      set "aux5=%aux5:~-5%"
          rem repair unacceptable format mask ###.#0 to ###.00
      set "auxx=%aux5:~3,1%
      if "%auxx%"==" " set "aux5=%aux5:~0,3%0%aux5:~4%"
          REM       rem change format mask from ###.00 to common ##0.00
          REM   set "auxx=%aux5:~2,1%
          REM   if "%auxx%"==" " set "aux5=%aux5:~0,2%0%aux5:~3%" 
      set "aux6=%aux5:~0,3%.%aux5:~3%"
    ENDLOCAL&set "%1=%aux6%"
    goto :eof
    

    输出:

    ==> D:\bat\SO\37338476a.bat
    ---
    8137 [MB] Total Physical Memory
    4166 [MB] Available Physical Memory
    ---
    _memo_avail=4166
    _memo_inuse=3971
    _memo_total=8137
    _perc_avail= 51.19
    _perc_inuse= 48.80
    _perc__suma= 99.99
    
    ==>
    

    准确度、容差(使用 8 GiB 安装内存测量):==> 良好

    • Capacity=8589934592                来自Win32_PhysicalMemory class== 8 GiB
    • TotalPhysicalMemory=8531865600     来自Win32_ComputerSystem class== 8136.62 MiB
    • Total Physical Memory:   8 137 MB 来自 systeminfo 命令 == 8137 MiB

    响应时间(systeminfo 比 wmic 慢很多):==> 差

    【讨论】:

    • BY 使用systeminfo很容易得到以MB为单位的输出,但是它会检查系统的所有hotfix和NIC信息,我希望我们在服务器中实现这个脚本时systeminfo不是一个好主意,它会占用更多的cpu,所以只有我更喜欢WMIC
    • 所以请帮助我在 WMIC 脚本中获得相同的输出
    • @T.Anand 查看my comment to your question 您可能需要调整npocmaka's answer 以匹配您的情况和要求。抱歉,我无法为 StackExchange.com 上的任何人编写脚本。我只能接受挑战来解决有趣的问题……
    【解决方案3】:

    您可以更改输出以满足您的需要:

    @if (@X)==(@Y) @end /* JScript comment
        @echo off
        cscript //E:JScript //nologo "%~f0"
        exit /b %errorlevel%
    
    @if (@X)==(@Y) @end JScript comment */
    
    var aBytes=GetObject('winmgmts:').ExecQuery('Select * from Win32_PerfFormattedData_PerfOS_Memory').ItemIndex(0).AvailableBytes;
    var tBytes=GetObject('winmgmts:').ExecQuery('Select * from Win32_ComputerSystem').ItemIndex(0).TotalPhysicalMemory;
    WScript.Echo("available:"+aBytes+"\ntotal:"+tBytes);
    var totalMemoryUsed=(tBytes-aBytes)*100/tBytes;
    WScript.Echo("used in % -"+totalMemoryUsed);
    

    【讨论】:

      猜你喜欢
      • 2021-07-24
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 2015-01-03
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2012-10-19
      相关资源
      最近更新 更多