Как исправить "отсутствующий операнд" в пакетном скрипте - PullRequest
0 голосов
/ 27 мая 2020

У меня есть пакетный скрипт, который производит точный окончательный результат, который я ищу, но есть два сообщения "пропущенный операнд" до окончательного вывода. Я просмотрел десятки потоков в Интернете, пытаясь выяснить, как разрешить / предотвратить это сообщение, но я еще не смог найти исправление ...

Вот мой сценарий:

:Start
cls
@echo off

REM -------------------------------------------------------------------------
REM [ Remotely Verify Max RAM Capacity & Required Stick Sizes & Quantities) ]
REM -------------------------------------------------------------------------

Set /P "Computer=Enter the Computer Name: "

FOR /F "tokens=1,2 skip=1" %%G in ('wmic /node:"%Computer%" memphysical get MaxCapacity^, MemoryDevices') do (set /A "ramcapacity=%%G" & set /A "ramslots=%%H")
set /A "trueram=ramcapacity/1048576"
set /A "sticksizes=ramcapacity/1048576/ramslots"
echo Max RAM = %trueram%GB / %ramslots% sticks @ %sticksizes%GB

Goto End

:End

А вот пример вывода:

Missing operand.
Missing operand.
Max RAM = 64GB / 4 sticks @ 16GB

Поскольку я могу получить ожидаемый результат, отсутствующие сообщения операндов не нарушают условия сделки, но я ' Я все еще хотел бы выяснить, почему они возникают и как их предотвратить (если возможно).

Ответы [ 2 ]

3 голосов
/ 27 мая 2020

Это потому, что wcic имеет уродливое окончание строки CRCRLF вместо просто CRLF. Первый CR становится частью переменной %%G / %%H. Поскольку расчет правильный, вы можете просто подавить сообщение об ошибке с помощью 2>nul. Чтобы действительно вылечить проблему, самый безопасный и наиболее распространенный способ c - это постобработка значения с помощью другого for l oop:

@echo off
setlocal
FOR /F "tokens=1,2 skip=1" %%G in ('wmic memphysical get MaxCapacity^, MemoryDevices') do (
  for /f %%a in ("%%G") do set "ramcapacity=%%a"
  for /f %%a in ("%%H") do set "ramslots=%%a"
)
set /A "trueram=ramcapacity/1048576"
set /A "sticksizes=ramcapacity/1048576/ramslots"
echo Max RAM = %trueram%GB / %ramslots% sticks @ %sticksizes%GB

Примечание: вам действительно не нужно set /a в пределах for l oop. Чтобы просто присвоить номер переменной, достаточно set var=12345. Используйте set /a только для арифметики c.

Другой способ - избегать использования строки в конце строки. В следующем коде я добавил (но не использовал) третий токен (Width - последний доступный с wmic memphysical, поскольку wmic сортирует столбцы в алфавитном порядке), поэтому как %%G, так и %%H не включать CR. Я также использовал ^|findstr /v "^$", чтобы пропустить пустые строки (которые перезапишут наши переменные пустыми значениями):

@echo off
setlocal
FOR /F "skip=1 tokens=1,2" %%G in ('wmic memphysical get MaxCapacity^, MemoryDevices^,Width ^|findstr /v "^$"') do (
  set "ramcapacity=%%G"
  set "ramslots=%%H"
)
set /A "trueram=ramcapacity/1048576"
set /A "sticksizes=ramcapacity/1048576/ramslots"
echo Max RAM = %trueram%GB / %ramslots% sticks @ %sticksizes%GB 
2 голосов
/ 27 мая 2020

Вместо:

do (set /A "ramcapacity=%%G" & set /A "ramslots=%%H")

просто напишите:

do (set /A "ramcapacity=%%G" & set /A "ramslots=%%H") 2> nul

Часть 2> nul просто подавляет сообщения об ошибках.


Причиной root сообщения об ошибке является тот факт, что wmic возвращает текст Unicode, который for /F не может правильно преобразовать его в текст ASCII / ANSI, потому что он оставляет потерянные символы возврата каретки. Итак, в вашей ситуации после строки с информацией о памяти for /F повторяется еще раз, делая доступным такой символ в %%G, следовательно, пытаясь использовать его set /A "ramcapacity=%%G", что, наконец, возвращает сообщение об ошибке.

Чтобы избежать таких артефактов преобразования, вложите еще один for /F l oop, например:

for /F "skip=1 delims=" %%I in ('
    wmic /NODE:"%Computer%" MemPhysical get MaxCapacity^,MemoryDevices
') do (
    for /F "tokens=1,2" %%G in ("%%I") do (
        set /A "ramcapacity=%%G" & set /A "ramslots=%%H"
    )
)

В общем, я рекомендую использовать опцию /VALUE для wmic команда, что приводит к следующему выводу:

MaxCapacity=67108864
MemoryDevices=4

, потому что это позволяет избежать заполнения строк значений пробелами справа (хотя они не мешают в вашей ситуации, так как вы используете set /A):

set "ramcapacity=" & rem // (ensure this variable is initially undefined)
for /F "delims=" %%I in ('
    wmic /NODE:"%Computer%" MemPhysical get MaxCapacity^,MemoryDevices /VALUE
') do (
    for /F "tokens=2 delims==" %%J in ("%%I") do (
        rem // The condition ensures that the only first line is processed:
        if not defined ramcapacity set /A "ramcapacity=%%J"
        rem // Here is no condition, so the last (second) line is relevant:
        set /A "ramslots=%%J"
    )
)

Я бы даже go на один шаг дальше и избегал явного определения переменных, таких как ramcapacity и ramslots, потому что возвращенные строки MaxCapacity=67108864 и MemoryDevices=4 уже выглядят как идеальные выражения для команды set:

for /F "delims=" %%I in ('
    wmic /NODE:"%Computer%" MemPhysical get MaxCapacity^,MemoryDevices /VALUE
') do (
    for /F "delims=" %%J in ("%%I") do (
        rem // This implicitly defines variables `MaxCapacity` and `MemoryDevices`:
        set /A "%%J"
    )
)
set /A "TrueRAM=MaxCapacity/(1<<20), StickSizes=TrueRAM/MemoryDevices"
echo Max RAM = %TrueRAM% GiB / %MemoryDevices% sticks @ %StickSizes% GiB
...