Batch: Vermeidung spezifischer Konflikte in FOR-Schleifen

Batch: Vermeidung spezifischer Konflikte in FOR-Schleifen

Problem: unerwartetes Verhalten (einzelnes Duplikat) in der FOR-Schleife.

Ich versuche, eine einfache Batch-VBScript-Schnittstelle zum Ein- und Aushängen von Datenträgern und anderen Aufgaben zu erstellen („Voltask“). Ein zentraler Teil der Funktion ist die eindeutige Identifizierung jedes Datenträgers, die ich durch Analysieren der Ausgabe von MOUNTVOL erreichen möchte:

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

Die erste Analyse gibt einigen Unterprogrammen, was sie brauchen, und macht die Daten im Allgemeinen angenehmer zu handhaben. Jede relevante Zeile von MOUNTVOL wird in einer separaten Variablennummer gespeichert.

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

Der nächste Schritt besteht darin, diese einfache Ausgabe zu nehmen und einen Schritt näher an die Kombination entsprechender Buchstaben und Namen heranzugehen: 1 2 3 4 5 -> 11 12 21 22 31... Auf diese Weise würde die erste Zahl immer einen Band darstellen und die letztere den dem Band entsprechenden Datentyp, 1=Name, 2=Buchstabe.

Ich versuche dies zu erreichen, indem ich die zuvor gewonnenen Daten mit folgendem Verfahren analysiere:

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

Nur um die Arithmetik zu verdeutlichen: Die Zählungen führen dazu, dass A bei jedem zweiten Lauf zunimmt und B zwischen 1 und 2 variiert.

Die angezeigte Ausgabe lautet:

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 und 62 sind Duplikate von 11 und 12. Das wäre reiner Zufall, denn die Werte von %G an genau dieser Stelle sind ebenfalls 11 und 12. Das brachte mich zu dem Schluss, dass … ich es einfach nicht sehe.

Wird !%%G! irgendwie falsch interpretiert oder habe ich mich beim Zählen geirrt? Ich habe meinen Kopf so lange auf den Bildschirm geschlagen, dass ich für jeden Tipp wirklich dankbar bin!

EDIT: Nach einer gründlichen Pause wurde mir klar, dass es zwangsläufig zu Konflikten kommt, wenn %%G 10 überschreitet, da !%%G! als !11! und !12! interpretiert wird, die sich sowohl auf Variablen der ersten als auch der zweiten Analyse beziehen. Dies führt zu Duplikaten. Das Dilemma bleibt jedoch bestehen: Wie kann dies vermieden werden?

Das Einrichten einer weiteren Lokalisierungsebene würde das Problem auf Kosten der Erstellung weiterer Ebenen lösen; scheint aber keine praktikable Option zu sein. Ich könnte Buchstaben statt Zahlen als Variablen verwenden, aber das würde die Arithmetik zerstören. *Derzeit untersuche ich die Verwendung von shift, um set /a count+=1 durch ein Äquivalent für Buchstaben zu ersetzen, aber bisher ohne Erfolg.

Antwort1

Sie können Ihren Code einfach korrigieren, indem Sie in Ihren endgültigen Variablennamen ein Trennzeichen zwischen die beiden Zahlen setzen. Ich verwende einen Punkt:

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

Oder Sie könnten vor jeden Namen ein Präfix setzen. Das ist eine gute Idee, da Sie einen Variablennamen, der mit einer Ziffer beginnt, nicht mit normaler Erweiterung erweitern können, da er mit einem Batch-Argument wie verwechselt würde %1. Bei Ihrem Code ist das kein Problem, da Sie eine verzögerte Erweiterung verwenden. Aber Variablen, die mit einer Ziffer beginnen, sollten Sie generell vermeiden.

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

Ich würde wahrscheinlich beides tun. Mir gefällt, dass die Variable mit etwas anderem als einer Ziffer beginnt, und optisch gefällt mir die Trennung der beiden Zahlen:

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

Ihr Code könnte erheblich vereinfacht werden:

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

Das sollte ergeben:

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

Durch die Vereinfachung des Codes auf die Verwendung einer einzigen Schleife ohne Zwischenvariablen ist technisch gesehen kein Präfix oder Trennzeichen im Variablennamen erforderlich. Sie könnten in meiner Schleife einfach Folgendes verwenden:

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

Aber ich würde trotzdem das Präfix und das Trennzeichen beibehalten.

Auf einem Computer können 10 oder mehr Datenträger vorhanden sein – meiner hat 10. Wie Scott vorschlägt, können Sie dem Wert 100 hinzufügen, um einen Variablennamen mit fester Breite zu erhalten, der bis zu 99 Datenträger unterstützt. Ich würde auch eine Teilzeichenfolgenoperation verwenden, um Werte mit dem Präfix null zu erhalten, beginnend mit 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
)

Antwort2

Entfernen Sie einfach Duplikate (Konflikte) aus den Variablennamen, indem SiePräfixierungdurch Buchstaben. Verwenden Sie beispielsweise beim ersten Durchgang , A1, A2, A3..., und/oder beim zweiten Durchgang B11, B12, B21, , ...,.B22

In solchen Situationen finde ich manchmal, dass nicht einheitliche VariablennamenLängen verursacht einige Schwierigkeiten. (Beispielsweise sind A1... A9zwei Zeichen, aber A10usw. sind drei Zeichen.) Manchmal handhabe ich das so, dass ich die Nummerierung bei 10 oder 11 oder 100 oder 101 beginne. Wenn Sie beispielsweise mit beginnen A10, können Sie 90 Eingabezeilen haben und nur bis gehen A99.

verwandte Informationen