2

Проблема: неожиданное поведение (одиночный дубликат) в цикле FOR.

Я пытаюсь сделать простой интерфейс batch-vbscript для монтирования и демонтажа томов, среди других задач ("Voltask"). Центральная часть функции - уникальная идентификация каждого тома, чего я пытаюсь достичь, анализируя вывод из MOUNTVOL:

\\?\Volume{d35e9775-0176-11d6-a06d-806e6f6e6963}\
    H:\
\\?\Volume{d35e9776-0176-11d6-a06d-806e6f6e6963}\
    F:\
\\?\Volume{6537febd-01bc-11d6-adb5-806e6f6e6963}\
    *** NO MOUNT POINTS ***
\\?\Volume{3fb54500-a257-11e4-8d8d-806e6f6e6963}\
    *** NO MOUNT POINTS ***
\\?\Volume{6537febe-01bc-11d6-adb5-806e6f6e6963}\
    C:\
\\?\Volume{6537fec3-01bc-11d6-adb5-806e6f6e6963}\
    A:\
\\?\Volume{6537fec1-01bc-11d6-adb5-806e6f6e6963}\
    D:\
\\?\Volume{6537fec2-01bc-11d6-adb5-806e6f6e6963}\
    E:\

Первый анализ дает некоторым подпрограммам то, что им нужно, и делает данные в целом более удобными для обработки. Каждая соответствующая строка из MOUNTVOL хранится в отдельном номере переменной.

@ECHO OFF & SETLOCAL enabledelayedexpansion & SET count=0
REM Basic parse
FOR /F "usebackq" %%5 IN (`
MOUNTVOL ^| FINDSTR /c:\ /c:*
`) DO (
SET /a count+=1
SET !count!=%%5
)

Следующий шаг - взять этот простой вывод и сделать шаг ближе к объединению соответствующих букв и имен: 1 2 3 4 5 -> 11 12 21 22 31 ... Таким образом, первое число всегда будет представлять один том, а второе - тип данных, соответствующий этому объему, 1 = имя, 2 = буква.

Я пытаюсь добиться этого путем анализа ранее полученных данных с помощью:

FOR /L %%G IN (1,1,%count%) DO (
SET /a ODD=%%G %%2
IF !ODD! EQU 1 (
SET A=%%G
SET /a A-=!C!
SET /a C+=1
SET B=1
) 
REM Intentionally not using "ELSE"
IF !ODD! EQU 0 (
SET A=%%G
SET /a A-=!C!
SET /a B+=1
)
SET !A!!B!=!%%G!
ECHO !A!!B! Has Data !%%G!
)

Просто чтобы прояснить арифметику: отсчеты приводят к тому, что A увеличивается с каждым вторым прогоном, а B изменяется от 1 до 2.

Результирующий вывод как показано:

11 Has Data \\?\Volume{d35e9775-0176-11d6-a06d-806e6f6e6963}\
12 Has Data H:\
21 Has Data \\?\Volume{d35e9776-0176-11d6-a06d-806e6f6e6963}\
22 Has Data F:\
31 Has Data \\?\Volume{6537febd-01bc-11d6-adb5-806e6f6e6963}\
32 Has Data ***
41 Has Data \\?\Volume{3fb54500-a257-11e4-8d8d-806e6f6e6963}\
42 Has Data ***
51 Has Data \\?\Volume{6537febe-01bc-11d6-adb5-806e6f6e6963}\
52 Has Data C:\
61 Has Data \\?\Volume{d35e9775-0176-11d6-a06d-806e6f6e6963}\
62 Has Data H:\
71 Has Data \\?\Volume{6537fec1-01bc-11d6-adb5-806e6f6e6963}\
72 Has Data D:\
81 Has Data \\?\Volume{6537fec2-01bc-11d6-adb5-806e6f6e6963}\
82 Has Data E:\

61 и 62 являются дубликатами 11 и 12. Это было бы просто совпадением, поскольку значения% G в этой точной точке также равны 11 и 12. Это привело меня к выводу, что ... я просто не вижу этого.

Является !%%Г! как-то меня неправильно истолковали или я ошибся с подсчетами? Я так долго бился головой об экран, что буду очень признателен за любые советы!

РЕДАКТИРОВАТЬ: После тщательного перерыва я понял, что после %% G проходит 10, конфликты обязательно произойдут как!%%Г! интерпретируется как!11! а также !12 !, которые относятся как к переменным первого, так и второго анализа. Это приводит к дубликатам. Однако остается дилемма: как этого избежать?

Установка другого уровня локализации решит проблему за счет создания других; не представляется приемлемым вариантом. Я мог бы использовать буквы вместо чисел в качестве переменных, но это нарушило бы арифметику. * В настоящее время исследуем использование shift для замены set /a count+= 1 эквивалентом букв, но пока безрезультатно.

2 ответа2

3

Вы можете исправить свой код, просто поместив разделитель между двумя числами в ваших окончательных именах переменных - я буду использовать точку:

SET !A!.!B!=!%%G!
ECHO !A!.!B! Has Data !%%G!

Или вы можете поставить префикс перед каждым именем. Это хорошая идея, потому что вы не можете развернуть имя переменной, начинающееся с цифры с нормальным расширением, потому что оно будет перепутано с аргументом пакета, таким как %1 . Не проблема с вашим кодом, так как вы используете отложенное расширение. Но переменные, начинающиеся с цифры, это то, чего обычно следует избегать.

SET V!A!!B!=!%%G!
ECHO V!A!!B! Has Data !%%G!

Я бы наверное сделал и то и другое. Мне нравится переменная, начинающаяся с чего-то отличного от цифры, и визуально мне нравится разделение двух чисел:

SET V!A!.!B!=!%%G!
ECHO V!A!.!B! Has Data !%%G!

Ваш код может быть значительно упрощен:

@echo off
setlocal enableDelayedExpansion
set /a count=0
for /f %%A in ('mountvol ^| findstr /l "\ *"') do (
  set /a "A=count/2+1, B=count%%2+1, count+=1"
  set "V!A!.!B!=%%A"
  echo V!A!.!B!=%%A
)

Который должен дать:

V1.1 Has Data \\?\Volume{d35e9775-0176-11d6-a06d-806e6f6e6963}\
V1.2 Has Data H:\
V2.1 Has Data \\?\Volume{d35e9776-0176-11d6-a06d-806e6f6e6963}\
V2.2 Has Data F:\
V3.1 Has Data \\?\Volume{6537febd-01bc-11d6-adb5-806e6f6e6963}\
V3.2 Has Data ***
V4.1 Has Data \\?\Volume{3fb54500-a257-11e4-8d8d-806e6f6e6963}\
V4.2 Has Data ***
V5.1 Has Data \\?\Volume{6537febe-01bc-11d6-adb5-806e6f6e6963}\
V5.2 Has Data C:\
V6.1 Has Data \\?\Volume{6537fec3-01bc-11d6-adb5-806e6f6e6963}\
V6.2 Has Data A:\
V7.1 Has Data \\?\Volume{6537fec1-01bc-11d6-adb5-806e6f6e6963}\
V7.2 Has Data D:\
V8.1 Has Data \\?\Volume{6537fec2-01bc-11d6-adb5-806e6f6e6963}\
V8.2 Has Data E:\

Упрощая код для использования только одного цикла без промежуточных переменных, технически нет необходимости использовать префикс или разделитель в имени переменной. Вы можете просто использовать следующее в моем цикле:

  set "!A!!B!=%%A"
  echo !A!!B! Has Data %%A

Но я все равно сохранил бы префикс и разделитель.

На машине может быть 10 или более томов - у меня их 10. Как предполагает Скотт, вы можете добавить 100 к значению, чтобы получить имя переменной фиксированной ширины, которая поддерживает до 99 томов. Я также использовал бы операцию с подстрокой, чтобы получить нулевые префиксные значения, начиная с 01 .

@echo off
setlocal enableDelayedExpansion
set /a count=0
for /f %%A in ('mountvol ^| findstr /l "\ *"') do (
  set /a "A=count/2+101, B=count%%2+1, count+=1"
  set "V!A:~-2!.!B!=%%A"
  echo V!A:~-2!.!B!=%%A
)
1

Просто удалите дубликаты (deconflict) имен переменных, поставив перед ними префиксы.  Например, на первом проходе используйте A1 , A2 , A3 , ... и / или используйте B11 , B12 , B21 , B22 , ..., на втором проходе.

В подобных ситуациях я иногда обнаруживаю, что неодинаковые длины имен переменных вызывают определенные трудности.  (Например, A1 ... A9 - два символа, но затем A10 и т.д. - три символа.)  Иногда я справляюсь с этим, начиная нумерацию с 10 или 11, или 100 или 101.  Например, если вы начинаете с A10 , у вас может быть 90 строк ввода и только до A99 .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .