批次:避免 FOR 迴圈中的特定衝突

批次:避免 FOR 迴圈中的特定衝突

問題:FOR 循環中出現意外行為(單一重複)。

我正在嘗試製作一個簡單的批次 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 經過 10 後,必然會發生衝突,因為 !%%G!被解釋為!11!和 !12!,它們指的是第一個和第二個解析變數。這會導致重複。然而,困境仍然存在:如何避免這種情況?

設定另一層本地化可以解決問題,但代價是建立其他層。似乎不是一個可行的選擇。我可以使用字母而不是數字作為變量,但這會破壞算術。 *目前正在研究使用 shift 將 set /a count+=1 替換為字母的等效項,但到目前為止還沒有結果。

答案1

您只需在最終變數名稱中的兩個數字之間放置分隔符號即可修復程式碼 - 我將使用句點:

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 個。我還將使用子字串操作來獲取以 . 開頭的零前綴值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
)

答案2

只需透過以下方式消除變數名稱的重複(消除衝突)前綴他們用字母。例如,在第一遍中,使用A1, A2, A3, ...,和/或在第二遍中使用B11, B12, B21, , ..., 。B22

在這種情況下,我有時會發現變數名稱不統一長度 造成一定的困難。 (例如,A1...A9是兩個字符,但 then等是三個字符。)有時我會A10通過從 10 或 11、100 或 101 開始編號來處理這個問題。A10輸入,最多只能達到A99.

相關內容