저도 초보 수준인데 이런 말씀 드리긴 뭐하지만, 이 글은 초보 분들에게 별 재미가 없을테니 초보 분들은 그냥 넘겨주세요. 배치파일 자주 작성하시는 분들을 위한 글입니다.

저는 FOR 구문에 대해 특별히 공부한 것이 없습니다. 그냥 /? 붙여서 나온 도움말을 보고 익힌게 다입니다. 그래서 여기서 다룰 내용은 매우 기초적인 것들입니다. 하지만 이러한 기초적인 내용을 익혀두면 응용하기에 따라 매우 편리하게 사용할 수 있습니다. 제가 윈도우 하드에서 설치하기나 PE, VHD 관련 글에 첨부하는 스크립트에는 대부분 FOR 구문이 포함되어 있습니다. 조금만 익혀두면 적어도 제가 사용하는 수준만큼은 도달할 수 있습니다.



1. 기본 구조

for /f "옵션" %변수 in (메롱) do 명령어

FOR 구문의 기본 구조입니다. (메롱) 안에 있는 문자열, 파일, 명령어의 출력값 등에 대해 DO 이하 명령어를 반복 수행하도록 지시합니다. 그런데 %변수의 경우 일괄 배치파일 안에 들어갈 때는 %%변수 형태로 적어줘야 합니다. 또한 %변수는 대소문자를 구분합니다. 즉 %a와 %A는 다릅니다.

예제)
for %a in (*.msu) do start /wait wusa %a /quiet /norestart

위 예는 현재 위치에 존재하는 확장자 msu 파일에 대해 wusa라는  "윈도우 업데이트 독립 실행형 설치 관리자" 툴을 사용하여 반복해서 설치를 수행합니다. 아 물론 이건 윈도우 비스타, 세븐 기준입니다.

XP 업데이트라면 아래 예제처럼 하면 되겠지요.

예제)
for %a in (*.exe) do start /wait %a /quiet /norestart

위 예는 현재 위치에 존재하는 확장자 exe 파일에 대해 반복해서 실행을 수행합니다.


예제)
for %%a in (C: D: E: F: G: H: I: J: K: L: M: N: O: P: Q: R: S: T: U: V: W: X: Y: Z:) do (
     if exist %%a\WIN51 set CDROM=%%a
)

위 예는 C ~ Z 드라이브 중에 WIN51 이라는 파일을 포함하고 있다면 해당 드라이브를 CDROM 이라는 변수로 지정해줍니다. 제가 WIN51 이라는 태그파일을 넣은 이유는 XP 설치 CD를 예로 든 것입니다. 만약 XP 무인설치를 구성하는데 추가 프로그램이 CD롬에서 실행되어야 한다면 CD롬 드라이브 문자를 알아내기 위해 저렇게 사용할 수 있겠지요. 이렇게 한번 지정해두면 예를 들어 CD롬 안에 UTILS 폴더가 있고 그 안에 있는 AAA.EXE 파일을 실행해야 한다면

%CDROM%\UTILS\AAA.EXE

위 예처럼 넣으면 되겠지요.



2. 옵션

저는 tokens= 옵션이 FOR 구문의 꽃이라 생각합니다. 토큰을 잘 활용하면 재미있는 스크립트를 많이 만들어낼 수 있습니다. 제가 자주 사용하는 옵션 몇가지만 간단히 설명드리겠습니다.

tokens=
FOR 구문은 각 행별로 분석하는데 이때 토큰은 각 행의 몇번째 문자열을 전달해줄지 지정합니다. 문자열의 기본 구분단위는 공백입니다.

for /f "tokens=3" %a in ("I LOVE YOU") do echo %a

위 예제를 입력하면 결과가 어떻게 될까요? 바로 세번째 문자열인 YOU가 출력됩니다. 토큰이 뭔지 이해되시죠?


delims=
토큰은 기본적으로 공백으로 구분하는데 delims 뒤에 구분 문자를 지정하면 그걸로 대체됩니다.

for /f "tokens=3" %a in ("I LOVE YOU-SO MUCH") do echo %a

for /f "tokens=2 delims=-" %a in ("I LOVE YOU-SO MUCH") do echo %a

for /f "tokens=4 delims=- " %a in ("I LOVE YOU-SO MUCH") do echo %a

위 예제를 각각 입력해보시면 delims의 기능을 이해하실 수 있을겁니다.
첫번째 줄은 delims가 없기 때문에 공백이 구분 문자라서 세번째 토큰은 YOU-SO가 됩니다.
두번째 줄은 - 문자가 구분자라서 두번째 토큰은 SO MUCH가 됩니다.
세번째 줄은 - 와 공백이 동시에 구분자라서 네번째 토큰은 SO가 됩니다.


skip=
위에서부터 몇줄까지 무시할지 결정해줍니다. 필요한 토큰이 세번째 줄에 있다면 처음 두줄은 무시해줘도 되겠지요. 이 경우 skip=2 라고 입력하면 됩니다.


usebackq
이 옵션은 공백을 포함한 파일 경로 양쪽에 큰 따옴표를 붙여줄 때 사용합니다. 대신 이 옵션을 사용하면 괄호안에 들어갈 집합에 대한 표시를 조금 다르게 해야합니다. 원래는

(파일), ("문자열"), ('명령어') 인데 usebackq 옵션을 사용하면 ("파일"), ('문자열'), (`명령어`) 형태로 써야합니다.

예를 들어 MY NAME.TXT 라는 공백을 포함한 이름의 텍스트 파일이 존재하는 경우

for /f "tokens=1" %a in (MY NAME.TXT) do echo %a

for /f "tokens=1" %a in ("MY NAME.TXT") do echo %a

for /f "tokens=1 usebackq" %a in ("MY NAME.TXT") do echo %a

위 3가지 예중에 정상적으로 되는건 세번째밖에 없습니다.
첫번째 줄은 MY 라는 파일과 NAME.TXT 라는 파일을 찾기 때문에 실패하고
두번째 줄은 "MY NAME.TXT"를 파일 이름이 아닌 하나의 문자열로 인식하기 때문에 MY가 출력되고
세번째 줄만 원래 의도대로 MY NAME.TXT 파일 안에서 각 행의 첫번째 토큰을 출력해줍니다.
그러니까 FOR 구문에서 뒤쪽에 띄어쓰기 문제로 큰 따옴표를 사용해야 한다면 usebackq 옵션을 넣고 형식에 맞게 변경해야 합니다. 비단 괄호 안에 들어가는 파일 집합 뿐 아니라 DO 이하 구문에 들어가는 파일 경로에도 동일하게 적용된다는 점 알아두시면 됩니다.


/L
이 옵션은 단계적으로 증가, 감소하는 숫자 집합을 이용할 때 씁니다.

for /l %a in (1,1,5) do start /wait imagex /export h:\sources\install.wim %a e:\install.wim

위 예제는 Imagex로 윈도우 7 통합본 만들 때 일일이 export 시키는게 귀찮은 경우 사용할 수 있습니다. %a를 1부터 5까지 순서대로 받아주기 때문에 h:\sources\install.wim 이미지의 1~5 인덱스를 순서대로 e:\install.wim 파일로 export 시켜줄 수 있습니다. 만약 (5,-1,1) 하시면 5부터 1까지 차례대로 감소하면서 진행됩니다. 그러니까 (시작, 간격, 끝) 형태로 사용하시면 됩니다.



3. 실전 예제

현재 윈도우 7 사용중이신 분들의 에디션을 화면에 출력해보겠습니다. 에디션은 C:\Windows\System32\spp\tokens\skus 폴더 안을 보시면 확인이 가능합니다. 또는 레지스트리 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion 을 통해서도 확인할 수 있습니다. 이 두가지 방법을 각각 FOR 옵션에 적용해보겠습니다.

먼저 토큰 폴더를 활용하려면

dir /b C:\Windows\System32\spp\tokens\skus

이렇게 입력하면 저같은 경우

Security-SPP-Component-SKU-Ultimate

이렇게 출력되는데 이건 공백 기준으로 하나의 토큰이므로 delims=- 를 사용하여 구분해주면 에디션은 다섯번째 토큰이 됩니다.

@echo off
for /f "tokens=5 delims=-" %%a in ('dir /b %windir%\System32\spp\tokens\skus') do set sku=%%a
echo.
echo      당신은 현재 %SKU% 에디션을 사용하고 있습니다.
echo.
pause
exit

위 스크립트를 실행하면 화면에 에디션이 출력되겠지요?

다음은 레지스트리로 해봅시다.

reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v EditionID

이렇게 입력하면


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion
    EditionID    REG_SZ    Ultimate

저의 경우 이렇게 출력되는데 첫줄은 공백이고 에디션은 세번째 줄의 세번째 토큰입니다. 따라서 이렇게 구성하면 되겠네요.

@echo off
for /f "tokens=3 skip=2" %%a in ('reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v EditionID') do set SKU=%%a
echo.
echo      당신은 지금 %SKU% 에디션을 사용하고 있습니다.
echo.
pause
exit

위 스크립트를 실행해도 마찬가지로 화면에 에디션이 출력됩니다.


위 두가지 예제를 어디에 활용할 수 있을까요? 예를 들어 윈도우 7 $OEM$ 배포폴더 SetupComplete.cmd 파일에 처리해주면 에디션을 자동으로 인식해서 시디키를 입력해줄 수 있겠지요?

@echo off
for /f "tokens=5 delims=-" %%a in ('dir /b %windir%\System32\spp\tokens\skus') do set sku=%%a
if /i %sku%==starter cscript %windir%\system32\slmgr.vbs /ipk xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
if /i %sku%==homebasic cscript %windir%\system32\slmgr.vbs /ipk xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
if /i %sku%==homepremium cscript %windir%\system32\slmgr.vbs /ipk xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
if /i %sku%==professional cscript %windir%\system32\slmgr.vbs /ipk xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
if /i %sku%==ultimate cscript %windir%\system32\slmgr.vbs /ipk xxxxx-xxxxx-xxxxx-xxxxx-xxxxx



제가 활용하는 수준은 딱 이정도이고 나머지 FOR 옵션에 대해서는 잘 모르겠습니다. 그냥 한번 읽어봤을 때 웬지 제가 사용할 일이 없을 것 같은 옵션들은 이해하려는 노력을 하지 않게 되더군요. 그리고 이 FOR 구문은 그 자체보다 괄호 안에, DO 뒤에 무엇을 넣어주느냐에 따라 가치가 결정된다고 생각합니다. 보통 IF와 SET 구문을 곁들여서 활용하니 IF와 SET에 대해서도 사용법을 익혀두시면 좋을 것 같습니다.
  1. zxadqr15
    2010.08.28 21:21 신고

    1등인가요? ㅎㅎ 좋은 글 감사합니다`/

  2. 공부합시다.
    2010.08.28 21:25 신고

    안그래도 요즘 배치파일에 대해서 공부해볼려고 마음만 먹고 있었는데 때마침 이런 글이 올라왔네요. 앞으로도 종종 부탁드립니다.^^

  3. KFMS
    2010.08.28 22:07 신고

    @echo off
    for /f "tokens=5 delims=-" %%a in ('dir /b %windir%\System32\spp\tokens\skus') do set sku=%%a
    echo.
    echo 당신은 현재 %SKU% 에디션을 사용하고 있습니다.
    echo.
    pause
    exit
    이 문을 실행하면 '는 예상되지 않았습니다. 하고 바로 꺼지는 현상은 뭐죠?

    • BlogIcon snoopybox
      2010.08.28 22:23 신고
      수정 및 삭제

      메모장에 넣고 확장자 CMD나 BAT로 저장해서 실행하세요. 아니면 %%a를 %a로 바꾸시든가요. 본문에 설명되어 있습니다. 일괄 배치파일에선 변수 앞에 %%를 붙인다고.

  4. 이정길
    2010.08.28 23:27 신고

    공부중에 잠시 들렀는데 참고 하겠습니다 ^^

  5. Good7
    2010.08.29 01:34 신고

    안그래도 배치파일에 대해 알고 싶었는데 알려주셨네요.. 감사합니다.^^

  6. Fire~
    2010.09.27 10:58 신고

    좋은글 감사합니다.

  7. GOODU
    2011.05.06 02:40 신고

    정말 감사합니다. 궁금했었는데 인터넷 검색으로 찾아오게 되었습니다 ㅎㅎ
    궁금증이 확 풀렸네요 감사해요^^

  8. 궁금해요!!!
    2012.06.11 21:03 신고

    파일이
    SNMP_M_201110280210
    SNMP_M_201110280211
    SNMP_M_201110280212
    SNMP_M_201110280213
    SNMP_M_201110280214
    SNMP_M_201110280215
    SNMP_M_201110280216 이렇게 있는데요...

    SNMP_M_201110280216 빼고 나머지파일들의 이름가운데를 N으로 바꾸고 싶거든요....

    그래서 다음과같이 우선 추출해봤는데....

    @echo off
    FOR %%a IN (SNMP_M_*) DO (
    set abc=%%a
    echo %abc%
    )
    이렇게 하면
    SNMP_M_201110280216
    SNMP_M_201110280216
    SNMP_M_201110280216
    SNMP_M_201110280216
    SNMP_M_201110280216
    SNMP_M_201110280216
    SNMP_M_201110280216
    나와요~

    이렇게 나오게 하려면 어케 해야죠?
    SNMP_M_201110280210
    SNMP_M_201110280211
    SNMP_M_201110280212
    SNMP_M_201110280213
    SNMP_M_201110280214
    SNMP_M_201110280215
    SNMP_M_201110280216

    • 지나가던삽질하던일인
      2015.01.01 19:57 신고
      수정 및 삭제

      해당 부분은 로컬 변수 설정 때문인듯요
      윈도우에서는 환경변수 문제 때문에 변수가 적용되는 스코프가 다른듯 해요. for문이 다 돌고 난 다음에 set 변수 내용이 나중에 출력되는것 같더라구요

      @echo off
      setlocal EnableDelayedExpansion
      FOR %%a IN (SNMP_M_*) DO (
      set abc=%%a
      echo !abc!
      )
      endlocal

  9. 천상천왕
    2012.10.27 19:10 신고

    도대체 뭐가 뭔지 모르겠네요

    그 옵션에서 보고 쭉 따라해봤는데
    도저히 하나도 모르겠습니다 ㅠㅠ

    스누피님

    제가 완전 초짜인가봐요 ㅋㅋ

    cmd에서도 레지스트리를 적용
    시킬수 있나보네요~^^*

  10. 정광호
    2013.10.08 14:00 신고

    안녕하세요. 저는 개발자인데 복잡한 다른 매뉴얼보다 실용적인 예제로 쉽게 설명해주셔서 큰 도움이 되었네요. 다만 for문 안에 %a는 %%a로 변경을 해야 제대로 동작이 되네요.
    또한 else문을 쓸때는 ") else ("<- else 와 괄호 사이에 공백이 있어야 오류가 나지 않네요.

  11. Shimss
    2016.09.20 10:22 신고

    감사 합니다
    윈도우 설치 부팅시 pe win 파일 찾아 구동 방법 연구중 입니다.