Пакет: Как исправить неправильное поведение при перезаписи переменных при разборе вывода

В пакетном файле я проверяю информацию Baseboard со следующим:
BaseboardCheck.cmd

@echo off
setlocal enabledelayedexpansion

for /f "tokens=1,2* delims==" %%a in ('wmic baseboard get /format:list') DO ( 

    if ["%%a"] EQU ["Product"] (
        set PlatformInfo=%%b

        if defined PlatformInfo (
            echo.!PlatformInfo!
            echo.!PlatformInfo!This overwrites the variable
        )
    )

    if ["%%a"] EQU ["Version"] (
        set BaseboardVersion=%%b

        if defined BaseboardVersion (
            echo.!BaseboardVersion!
            echo.!BaseboardVersion!This overwrites the variable
        )
    )   
)

Вышеуказанная проблема: переменные перезаписываются, а не добавляются, когда выводится echo.
Выход:

DX79SI
This overwrites the variable
AAG28808-600
This overwrites the variable

То, что я хотел бы получить это:

DX79SI
DX79SIThis overwrites the variable
AAG28808-600
AAG28808-600This overwrites the variable

Я потратил несколько часов на это (и буду продолжать это делать), но надеюсь, что кто-то еще столкнулся с этой проблемой. И я надеюсь, что любой другой, кто столкнется с этой проблемой анализа, сможет избежать ее в будущем.

Дополнительная проблема, которая возникает из-за этого, заключается в том, что она нарушает условную логику.

Обновить
После всей помощи я придумал это решение:

for /f "skip=2 tokens=1,2 delims=," %%a in ('wmic baseboard get Product^,Version^,Width /format:csv') do (

    set Platform=%%a
    set BaseboardVersion=%%b
)
echo.Platform: %Platform% 
echo.Version %BaseboardVersion%.

3 ответа

Решение

Да, у вас есть проблема, но это не то, что вы думаете.

wmic имеет определенное поведение: в конце каждой строки выводится дополнительный возврат каретки, то есть каждая строка заканчивается 0x0d 0x0d 0x0a

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

Как решить?

@echo off
setlocal enabledelayedexpansion

for /f "tokens=1,* delims==" %%a in ('wmic baseboard get /format:list') DO ( 


    if ["%%a"] EQU ["Product"] (
        for /f "delims=" %%c in ("%%b") do set "PlatformInfo=%%c"

        if defined PlatformInfo (
            echo(!PlatformInfo!
            echo(!PlatformInfo!This does not overwrite the variable
        )
    )

    if ["%%a"] EQU ["Version"] (
        for /f "delims=" %%c in ("%%b") do set "BaseboardVersion=%%c"

        if defined BaseboardVersion (
            echo(!BaseboardVersion!
            echo(!BaseboardVersion!This does not overwrite the variable
        )
    )   
)

В этом случае, не меняя логику кода, дополнительно for /f команда может быть использована для удаления дополнительного возврата каретки

Вау, было действительно трудно узнать, что здесь происходит.

Во-первых, я не мог поверить, что происходит при выполнении командного файла.

После многих испытаний я выполнил на Windows XP SP3 x86

wmic.exe baseboard get /format:list > Output.txt

и посмотрел на файл Output.txt со средством просмотра файлового менеджера Total Commander. Я видел 2 пустые строки сверху, но это не имеет большого значения. Поэтому я продолжил другие испытания.

Позже я открыл Output.txt в текстовом редакторе UltraEdit и сразу увидел в строке состояния U-DOS, что указывает на то, что выходной файл закодирован в UTF-16 с прямым порядком байтов, имеющим терминаторы строки DOS. Я переключился в режим редактирования hex и мог видеть

00000000h: FF FE 0D 00 0A 00 0D 00 0A 00 43 00 61 00 70 00 ; ÿþ........C.a.p.
00000010h: 74 00 69 00 6F 00 6E 00 3D 00                   ; t.i.o.n.=.

Таким образом, выходной файл действительно является Unicode-файлом с UTF-16 LE BOM. Там нет CR CR CR LF. Все окончания строки соответствуют паре CR LF (возврат каретки + перевод строки).

Теперь я искал в Stack Overflow вопросы с пакетным файлом, содержащим слова wmic Unicode, и обнаружил, что cmd каким-то образом пишет китайский текст в качестве вывода.

Принятый ответ dbenham не очень хорош, поскольку он создает ANSI-версию вывода Unicode: wmic.exe, но файл ANSI теперь действительно содержит 0D 0D 0A (= CR CR LF).

Лучше ответ Dharma Leonardi как решение с использованием команды type приводит к правильному преобразованию вывода Unicode в вывод ANSI, если вывод не содержит символов, недоступных в кодовой странице ANSI.

Но после изменения кода пакета для обработки вывода wmic.exe с кодировкой ANSI, строка с if defined BaseboardVersion всегда оценивается как true, хотя я не мог видеть, что переменная BaseboardVersion содержала какие-либо данные, и поэтому следующая строка привела к отображению статуса эха.

Мне потребовалось некоторое время, чтобы узнать, вставив set > Variables.txt выше условия и глядя на этот файл, что на моем компьютере строка версии просто один пробел. Значение Version было единственным значением всех ключей без строки справа от знака равенства, состоящей только из одного пробела.

Вот командный файл, который наконец-то работал на моем компьютере и дает ожидаемый результат:

@echo off
setlocal enabledelayedexpansion
wmic.exe /OUTPUT:"%TEMP%\UnicodeData.tmp" baseboard get /format:list
for /f "usebackq tokens=1,2* delims==" %%a in (`type "%TEMP%\UnicodeData.tmp"`) do (

    if "%%a" == "Product" (
        if not "%%b" == "" if not "%%b" == " " (
            set "PlatformInfo=%%b"
            echo !PlatformInfo!
            echo !PlatformInfo!This overwrites the variable
        )
    ) else if "%%a" == "Version" (
        if not "%%b" == "" if not "%%b" == " " (
            set "BaseboardVersion=%%b"
            echo !BaseboardVersion!
            echo !BaseboardVersion!This overwrites the variable
        )
    )
)
del "%TEMP%\UnicodeData.tmp"
endlocal

Как уже ответили, проблема с окончаниями строки wmic,

Вы можете преодолеть эту проблему, если не используете конец строки: wmic baseboard get Product,Version,Width использует три токена: Product, Version и Width (в большинстве случаев это empy). Таким образом, вывод будет: DX79SI,AAG28808-600, Мы используем токен 1 и токен 2, игнорируя токен 3 (это приведет к проблеме)

set Platform=undefined
set BaseboardVersion=undefined

for /f "tokens=1,2 delims=," %%a in ('wmic baseboard get Product^,Version^,Width^|findstr "."') do (
 set Platform=%%a
 set BaseboardVersion=%%b
)
echo it is a %Platform% with Version %BaseboardVersion%. No overwriting

Я также добавил delims=, в случае, если любая из строк содержит пробел (весьма вероятно, с product)

Другие вопросы по тегам