일괄 처리: FOR 루프에서 특정 충돌 방지

일괄 처리: FOR 루프에서 특정 충돌 방지

문제: FOR 루프에서 예상치 못한 동작(단일 중복)이 발생했습니다.

다른 작업("Voltask") 중에서 볼륨 마운트 및 마운트 해제를 위한 간단한 배치-vbscript 인터페이스를 만들려고 합니다. 이 기능의 핵심 부분은 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입니다! 뭔가 잘못 해석되고 있는 걸까요, 아니면 제가 계산에 실수를 한 걸까요? 너무 오랫동안 화면에 머리를 대고 있었는데 어떤 조언이라도 정말 감사하겠습니다!

편집: 철저하게 휴식을 취한 후 %%G가 10을 넘으면 충돌이 !%%G! !11!로 해석됩니다. 및 !12!는 첫 번째 및 두 번째 구문 분석 변수를 모두 나타냅니다. 이로 인해 중복이 발생합니다. 그러나 딜레마는 여전히 남아 있습니다. 이를 어떻게 피할 수 있을까요?

또 다른 현지화 계층을 설정하면 다른 계층을 만드는 대신 문제가 해결됩니다. 실행 가능한 옵션은 아닌 것 같습니다. 숫자 대신 문자를 변수로 사용할 수 있지만 이렇게 하면 산술이 깨질 수 있습니다. *현재 set /a count+=1을 문자에 해당하는 것으로 대체하기 위해 Shift를 사용하는 방법을 연구하고 있지만 지금까지는 소용이 없습니다.

답변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개입니다. Scott이 제안한 것처럼 값에 100을 추가하여 최대 99개의 볼륨을 지원하는 고정 너비 변수 이름을 얻을 수 있습니다. 또한 부분 문자열 작업을 사용하여 0으로 시작하는 접두사 값을 가져옵니다 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는 2개의 문자이지만 , A10등은 3개의 문자입니다.) 저는 때때로 10이나 11, 100이나 101에서 번호 매기기를 시작하여 이를 처리합니다. 예를 들어 로 시작 A10하면 90줄의 입력이 있고 최대 A99.

관련 정보