Lote: evitando conflitos específicos em loops FOR

2

Problema: comportamento inesperado (duplicado único) no loop FOR.

Estou tentando fazer uma interface simples batch-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 alcançar analisando a saída da 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 algumas sub-rotinas do que elas precisam e torna os dados geralmente mais agradáveis de serem manipulados. Cada linha relevante da MOUNTVOL é armazenada em um número 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 essa saída simples e aproximar um passo à combinação de letras e nomes correspondentes: 1 2 3 4 5 - > 11 12 21 22 31 ... Desta forma, o primeiro número representaria sempre um volume e o último o tipo de dados 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!
)

Apenas para esclarecer a aritmética: as contagens resultam em A aumentando a cada segundo 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. Como 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 concluir que ... apenas não vejo isso.

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

EDIT: Após uma pausa completa eu percebi que depois de %% G passar 10, os conflitos estão prestes a acontecer como o! %% G! é interpretado como! 11! e! 12 !, que se referem a variáveis de primeira e segunda análise. Isso resulta nas duplicatas. O dilema, no entanto, 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 com um equivalente para letras, mas até agora sem sucesso.

    
por Alex Oja 30.05.2015 / 03:34

2 respostas

3

Você pode corrigir seu código simplesmente colocando um delimitador entre os dois números em seus nomes de variáveis finais. Usarei um período:

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

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

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

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

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

Seu código pode ser simplificado drasticamente:

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

Qual 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 um 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 ainda manteria o prefixo e o delimitador.

Pode haver 10 ou mais volumes em uma máquina - o meu 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 valores zero pré-fixados, 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
)
    
por 30.05.2015 / 23:02
1

Simplesmente desduplique (desconstrua) os nomes das variáveis, prefixando-os 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 esse nome de variável não uniforme comprimentos causa alguma dificuldade. (Por exemplo, A1 ... A9 são dois caracteres, mas, em seguida, A10 , etc., são três caracteres. Eu às vezes ligo isso iniciando a numeração em 10 ou 11, ou 100 ou 101. Por exemplo, se você começar com A10 , você pode ter 90 linhas de entrada e ir até A99 .

    
por 30.05.2015 / 06:23

Tags