Lote: evitando conflitos específicos em loops FOR

Lote: evitando conflitos específicos em loops FOR

Problema: comportamento inesperado (duplicata única) no loop FOR.

Estou tentando fazer uma interface simples em lote-vbscript para montar e desmontar volumes, entre outras tarefas ("Voltask"). Uma parte central da função é a identificação exclusiva de cada volume, que estou tentando obter analisando a saída do 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:\

A primeira análise fornece a algumas sub-rotinas o que elas precisam e torna os dados geralmente mais agradáveis ​​de manusear. Cada linha relevante do MOUNTVOL é armazenada em um número de variável separado.

@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
)

O próximo passo é pegar esta saída simples e dar um passo mais perto de combinar letras e nomes correspondentes: 1 2 3 4 5 -> 11 12 21 22 31... Dessa forma, o primeiro número sempre representaria um volume e o último o tipo de dado correspondente ao volume, 1=nome, 2=letra.

Estou tentando conseguir isso analisando os dados obtidos anteriormente com:

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!
)

Só para esclarecer a aritmética: as contagens resultam em A aumentando a cada segunda execução e B variando entre 1 e 2.

A saída resultante conforme exibida é:

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 e 62 sendo duplicatas de 11 e 12. Por mera coincidência, isso seria curioso, pois os valores de% G neste exato ponto também são 11 e 12. Isso me leva a tirar a conclusão de que... eu simplesmente não Veja.

É !%%G! de alguma forma sendo mal interpretado ou cometi um erro com as contagens? Eu bati minha cabeça na tela por tanto tempo que eu realmente aprecio qualquer dica!

EDIT: Depois de uma pausa completa, percebi que depois que %%G passar de 10, conflitos acontecerão, pois !%%G! é interpretado como !11! e !12!, que se referem às variáveis ​​de primeira e segunda análise. Isso resulta em duplicatas. O dilema, porém, permanece: como evitar isso?

Definir outra camada de localização resolveria o problema em detrimento da criação de outras; não parece ser uma opção viável. Eu poderia usar letras em vez de números como variáveis, mas isso quebraria a aritmética. * Atualmente pesquisando usando shift para substituir set /a count+=1 por um equivalente para letras, mas até agora sem sucesso.

Responder1

Você pode corrigir seu código simplesmente colocando um delimitador entre os dois números nos nomes das variáveis ​​finais - usarei um ponto final:

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

Ou você pode colocar um prefixo antes de cada nome. Esta é uma boa ideia porque você não pode expandir um nome de variável começando com um dígito com expansão normal porque será confundido com um argumento em lote como %1. Não é um problema com o seu código, já que você usa expansão atrasada. Mas variáveis ​​que começam com um dígito são algo que geralmente deve ser evitado.

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

Eu provavelmente faria as duas coisas. Gosto da variável que começa com algo diferente de um dígito e, visualmente, gosto da separação dos dois números:

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

Seu código poderia ser drasticamente simplificado:

@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
)

O que deve render:

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:\

Ao simplificar o código para usar apenas um loop, sem variáveis ​​intermediárias, tecnicamente não há necessidade de prefixo ou delimitador no nome da variável. Você poderia simplesmente usar o seguinte no meu loop:

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

Mas eu ainda manteria o prefixo e o delimitador.

Pode haver 10 ou mais volumes em uma máquina - a minha tem 10. Como Scott sugere, você pode adicionar 100 ao valor para obter um nome de variável de largura fixa que suporte até 99 volumes. Eu também usaria uma operação de substring para obter zero valores prefixados, começando com 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
)

Responder2

Simplesmente desduplicar (desconflitar) os nomes das variáveisprefixandoeles com letras. Por exemplo, na primeira passagem, use A1, A2, A3, ..., e/ou use B11, B12, B21, B22, ..., na segunda passagem.

Em situações como esta, às vezes encontro aquele nome de variável não uniformecomprimentos causa alguma dificuldade. (Por exemplo, A1... A9são dois caracteres, mas então A10, etc., são três caracteres.) Às vezes eu resolvo isso iniciando a numeração em 10 ou 11, ou 100 ou 101. Por exemplo, se você começar com A10, você pode tem 90 linhas de entrada e só vai até A99.

informação relacionada