배치파일 기초 작성법
2010. 9. 29. 16:54 |
윈도우 일반
예전부터 한번 정리하려고 했는데 시간이 많이 걸리는 일이라 차일피일 미루다 오늘에야 올려봅니다. 처음에는 간단히 작성하려고 했는데 쓰다보니 글이 꽤 길어지더군요. 관심있는 분들만 읽어보세요. 여기서 다루는 내용을 완벽히 이해하시면 배치파일의 고수까지는 아니더라도 적어도 제가 활용하는 만큼은 만드실 수 있을 겁니다.
일단 잘 모르는 명령어가 있다면 도움말을 통해 기능을 익혀야겠지요. 사실 저는 이 배치파일을 거의 도움말을 통해 혼자서 익혔습니다. 예전에 어떤 분이 댓글로 저보고 배치파일을 진짜 잘 짠다고 하셨는데, 저도 어차피 도움말 보면서 익힌 것이니까 누구든지 도움말을 잘 이해하면 충분히 훌륭한 배치파일을 만들 수 있다고 생각합니다. 그런데 경우에 따라 도움말이 별로 친절하지 않을 수도 있습니다. 하지만 처음에는 이해되지 않던 말들도 시간이 지나고 경험이 쌓이면 나중에 다시 봤을 때 이해되는 경우가 많습니다. 예전에는 제가 FOR 구문의 대체 변수 참조 확장을 잘 이해하지 못했는데, 최근에는 잘 이해하게 되었습니다. 여러분도 이 도움말을 적극적으로 활용해보세요.
일반적으로 해당 명령어 뒤에 /? 를 붙이면 도움말이 나옵니다. 예를 들어 FOR 반복문의 사용법이 궁금하다면 FOR /? 해보면 되겠지요. 또는 HELP FOR 하셔도 동일한 결과를 얻을 수 있습니다. 그런데 도움말이 길면 스크롤 압박이 있으니 이 경우 도움말을 텍스트 파일로 저장해서 보셔도 되겠습니다. 뒤에 > 파일.txt 적어주시면 출력 결과를 텍스트 파일로 저장해줍니다.
예제)
FOR /? > "FOR 사용법.TXT"
ECHO는 글자 그대로 메아리를 뜻하는데, 화면에 메시지를 그대로 출력해줍니다. 배치파일에선 사용자에게 뭔가 설명해줘야 하는 부분이 많은데 이럴 때 ECHO를 활용합니다. 주로 SET, IF, GOTO 등과 결합해서 메뉴를 보여줄 때 많이 사용하지요.
예제)
ECHO 저는 에코입니다. 화면에 메시지를 보여주기 위해 사용되지요.
그런데 보통 배치파일 첫 줄에는 @ECHO OFF를 많이 적어줍니다. 만약 @ECHO OFF를 적어주지 않으면 각 명령줄을 화면에 그대로 한번 출력을 해주고 실행을 하기 때문에 화면이 많이 지저분해집니다. 그래서 보통은 배치파일의 첫 줄에서 ECHO를 OFF 시켜줍니다.
이 ECHO 명령어 역시 출력 결과를 텍스트파일로 저장할 수 있습니다. (리디렉션은 거의 모든 경우에 사용할 수 있습니다.) 예를 들어 DISKPART를 사용하는 경우 배치파일에선 DISKPART 다음줄부터 작동하지 않는데요, 이럴 때는 DISKPART 다음줄부터 사용될 명령어를 스크립트로 저장한 다음 DISKPART /S 스크립트 이렇게 사용해야 합니다.
예제)
@echo off
pushd %~dp0
echo create vdisk file=d:\test.vhd type=expandable maximum=20480 > test.txt
echo attach vdisk >> test.txt
echo create partition primary >> test.txt
echo format quick fs=ntfs >> test.txt
echo assign letter >> test.txt
echo exit >> test.txt
diskpart /s test.txt
exit
위 예제가 무슨 소린지 아직은 잘 이해되지 않을 수도 있는데, 아무튼 echo와 리디렉션을 활용하여 텍스트파일로 출력하는게 가능하기 때문에 배치파일 안에서 이렇게 새로운 배치파일이나 스크립트를 echo만을 사용하여 작성할 수 있습니다. 위 예제는 윈도우 7에서 D 드라이브에 TEST.VHD 파일을 자동으로 생성하는 기능을 합니다.
※ ESCAPE 문자
제가 한가지 빠트려서 보충합니다. echo로 리디렉션을 할때 만약에 >> 기호 역시도 echo의 일부분으로 포함시키고 싶다면 어떻게 해야 할까요? 예를 들어
echo dir /b >> list.txt >> test.txt
위 구문을 실행하면 test.txt에 dir /b 부분만 들어갑니다. 넣고싶은 문자열은 dir /b >> list.txt 인데 말이죠. 이런 경우 앞서 나온 >> 문자열을 리디렉션이 아니라고 Escape 시킬 필요가 있습니다. 이때는 caret 문자 ^ 를 붙여주면 됩니다. 그러니까 위 예제를 결과값이 의도대로 나오게 고치려면
echo dir /b ^>^> list.txt >> test.txt
이것 역시 제가 배치파일 초반에 항상 적어주는데요, 그 이유는 윈도우 7 때문입니다. 윈도우 7에선 특이하게도 UAC가 켜져있는 환경에서 배치파일을 관리자 권한으로 실행하는 경우 명령 프롬프트 위치가 C:\Windows\System32 기준으로 실행됩니다. 이게 왜 문제가 되냐하면 보통은 배치파일과 함께 같은 위치에 첨부 파일을 두고 다른 곳으로 복사해주는 명령어를 쓰거나 아니면 그 첨부파일을 실행하는 경우가 많은데, 이렇게 명령 프롬프트 위치가 변경되어 버리면 복사할 파일이나 실행할 파일의 절대경로를 적어야 합니다. 그런데 배치파일은 어느 위치에서 실행될지 아무도 모르죠. 따라서 복사할 파일의 절대경로도 그때그때 달라지게 됩니다. 물론 각 파일 경로 앞에 %~DP0를 일일이 붙여주면 되지만 그건 너무 귀찮은 일입니다. 따라서 이렇게 명령 프롬프트 위치를 배치파일이 있는 디렉터리로 되돌려주는게 훨씬 편합니다.
그런데 %~DP0의 의미가 궁금하실 것 같습니다. 이게 바로 FOR 구문의 대체 변수 참조 확장입니다. 자세한 내용은 FOR /? 입력해서 확인해보시구요, 저는 간단히 예제를 통해 설명드리겠습니다.
배치파일에서 %0는 그 배치파일의 전체 경로를 지칭합니다. %0 사이에 들어있는 ~dp는 %변수를 드라이브 문자와 경로로만 확장해줍니다. 예를 들어 제 컴퓨터 바탕화면에 예제.cmd 파일이 있는 경우
따라서 pushd %~dp0 라고 적으면 명령 프롬프트가 배치파일이 존재하는 위치로 돌아오게 됩니다. 이제 응용력이 뛰어나신 분들은 이런 생각을 하실 것 같습니다. "그렇다면 %~dpnx0 와 %~0 는 같은 값을 나타내겠군!" 네 그렇습니다. %~ 확장은 이처럼 한꺼번에 섞어서 사용해도 됩니다.
※ 참고로 PUSHD %~DP0 대신에 CD /D %~DP0 해도 상관은 없습니다.
이건 별로 중요하지 않은데, 배치파일을 실행했을 때 콘솔창에 표시되는 창 제목을 지정합니다. 원래 아무것도 지정하지 않으면 제목이 C:\Windows\System32\cmd.exe 인데, 이 부분을 변경하는 것입니다.
예제)
title 아이폰 4 AVI, MKV 동영상 자동 변환기
이것도 별로 중요하지는 않은데, 배치파일에선 콘솔창 크기를 지정하는 용도로 사용할 수 있습니다.
예제)
mode con cols=40 lines=11
콘솔창의 화면 색을 지정할 수 있습니다. 저는 까만 바탕에 흰 글씨가 마음에 들지만 예를 들어 파란 바탕에 흰 글씨로 지정할 수도 있겠지요.
0 = 검정색 8 = 회색
1 = 파랑색 9 = 연한 파랑색
2 = 초록색 A = 연한 초록색
3 = 옥색 B = 연한 옥색
4 = 빨강색 C = 연한 빨강색
5 = 자주색 D = 연한 자주색
6 = 노랑색 E = 연한 노랑색
7 = 흰색 F = 밝은 흰색
첫째 자리는 배경색이고 둘째 자리는 문자색입니다.
예제)
color 1F
화면을 깨끗하게 비웁니다. Clear Screen의 약자인데 보통 새로 메뉴를 출력해주는 경우 기존에 보이던 결과물 때문에 지저분하니까 CLS를 적어줍니다.
이것도 주로 안내문을 보여준 다음 적어줍니다. 일시정지 시켜둬야 사람들이 안내문을 읽어볼 수 있으니까요. 아무 키나 누르면 다음 명령어로 넘어갑니다. 저는 보통 배치파일을 작성하면서 중간중간에 PAUSE를 걸어넣고 파일을 실행해봅니다. 여기까지 오류없이 잘 작성되었는지 테스트 해보기 위함이죠.
지금부터가 진짜 배치파일입니다. 위에서 다뤘던 내용들은 그냥 준비운동 정도였고 배치파일에서 가장 많이 사용되는 (저만 가장 많이 사용하는지도 모르지만 ;;;) 구문이 바로 IF, FOR, SET 입니다. 이 3가지 구문이 배치파일의 꽃이라고 저는 생각합니다. 특히 저는 FOR 반복문을 매우 자주 사용하는 편인데, FOR 구문을 잘 활용하시면 "감히 배치파일로 이게 가능한가?" 생각했던 기능들도 훌륭히 만들어낼 수 있습니다.
IF는 말 그대로 "~인지 아닌지" 를 판단합니다. 만약 조건이 참이면 그 뒤에 나오는 명령어를 수행하고 참이 아니면 다음 줄로 넘어갑니다.
IF 문자열1==문자열2 명령어
예제)
set A=snoopy
if %A%==snoopy echo %A%는 snoopy와 같습니다.
set B=snoopybox
if %B%==snoopy echo %B%는 snoopy와 같습니다.
위 예제에서 첫번째 IF 구문은 조건이 참이기 때문에 "snoopy는 snoopy와 같습니다." 문구를 출력해줍니다. 하지만 두번째 IF 구문은 조건이 거짓이기 때문에 그 뒤에 나오는 echo 명령어는 무시됩니다.
IF 뒤에 /i 를 붙이시면 대소문자를 구분하지 않습니다. 이게 윈도우에선 IF 도움말에 잘못 표기되어 있네요. /i를 붙이면 대소문자 구분이 없고, 안 붙이면 대소문자를 구분합니다. 도움말에는 반대로 나와 있습니다.
숫자 비교에는 아래 비교연산자들이 사용됩니다.
EQU - 같음
NEQ - 같지 않음
LSS - 보다 작은
LEQ - 작거나 같음
GTR - 보다 큰
GEQ - 크거나 같음
예제)
if 5 equ 5 echo 5는 5와 같습니다.
if 5 neq 5 echo 5는 5와 같지 않습니다.
if 5 lss 5 echo 5는 5보다 작습니다.
if 5 leq 5 echo 5는 5보다 작거나 같습니다.
if 5 gtr 5 echo 5는 5보다 큽니다.
if 5 geq 5 echo 5는 5보다 크거나 같습니다.
위 예제에서는 1, 4, 6번째 줄만 참이기 때문에 뒤에 있는 echo가 출력되겠지요? 대충 저렇게 쓴다는 것만 알고 다음으로 넘어갑니다.
IF NOT은 IF와 반대로 생각하면 됩니다. 뒤에 나온 조건이 거짓인 경우에 IF NOT은 참이 되기 때문에 명령을 실행하게 됩니다.
예제)
if not snoopy==snoopy echo 과연 이 메시지가 출력될까?
위 예제를 실행하면 echo 다음에 나오는 메시지가 출력되지 않습니다. IF NOT이니까요. 하지만 만약에 if not snoopy==snoopybox 했다면 뒤에 나오는 명령어는 출력이 되었겠지요?
IF EXIST는 지정한 파일, 폴더가 존재하면 조건을 참으로 받아줍니다. 대략 아래와 같은 예를 만들어 보겠습니다.
예제)
if exist %windir%\syswow64 echo 이 윈도우는 64비트입니다.
if not exist %windir%\syswow64 echo 이 윈도우는 64비트가 아닙니다.
위 예제를 실행하면 64비트 윈도우인 경우 첫번째 echo 구문만 출력될 것이고, 32비트 윈도우인 경우 두번째 echo 구문만 출력될 것입니다. 마찬가지로 IF EXIST 구문도 IF NOT EXIST로 활용할 수 있습니다.
IF ERRORLEVEL 역시 제가 자주 사용하는 구문인데 마지막으로 실행된 프로그램의 종료코드가 무엇인지를 가지고 조건을 판단합니다. 일반적으로 아무런 오류가 없이 잘 실행된 경우에는 종료코드가 0입니다. 오류가 발생하면 종료코드는 1 이상입니다. IF ERRORLEVEL 1 하시면 종료코드가 1보다 크거나 같은 경우 참으로 인식합니다.
예제)
ren C:\Windows WindowsXP
if errorlevel 1 echo 윈도우 폴더는 이름을 변경할 수 없어요.
위 예제에서 첫번째 줄에 Windows 폴더 이름을 WindowsXP로 변경하라고 합니다. 말이 안 되죠? 당연히 오류가 발생할 수 밖에 없습니다. 따라서 두번째 줄에 있는 IF ERRORLEVEL 1 구문은 바로 위에서 오류가 발생했기 때문에 값이 참으로 지정되어 echo 뒤에 나오는 문구를 출력해줍니다.
ELSE는 IF랑 묶어서 사용하는데 여기서부터는 괄호를 사용하겠습니다. 이 괄호를 보기좋게 잘 써야 프로그램을 체계적으로 짤 수 있고, 나중에 자기가 봐도 흐름이 한 눈에 보입니다. 위에서 예를 들었던 윈도우 64비트 판별을 ELSE로 표현해보자면
예제)
if exist %windir%\syswow64 (
echo 이 윈도우는 64비트입니다.
) else (
echo 이 윈도우는 64비트가 아닙니다.
)
그러니까 ELSE는 IF 조건이 거짓인 경우 실행됩니다. IF가 옳으면 IF 구문 뒤에 있는 명령어가 실행되고, 그게 아니면 ELSE 뒤에 있는 명령어가 실행됩니다. 둘중에 하나만 무조건 실행되게 만드는 양자택일 구문이라 보시면 됩니다.
여기까지 대충 IF 구문에 대해 알아봤는데요 실전 예제 몇가지를 소개해봅니다. 아래는 제가 아이폰 4 AVI, MKV 동영상을 MP4로 한방에 변환하기 글에서 사용한 SRT 자막 통합 스크립트입니다.
예제)
set list=자막 통합에 실패한 파일 목록.txt
if exist *.srt (
if not exist temp md temp
for %%a in (*.srt) do (
if exist "%%~na.mp4" (
Tools\mediainfo "%%~na.mp4" > temp\temp1.txt
findstr /c:"Codec ID : tx3g" temp\temp1.txt > nul
if errorlevel 1 (
Tools\mp4box -add "%%a":lang=ko:hdlr=sbtl "%%~na.mp4"
if errorlevel 1 echo %%~na.mp4 >> "%list%"
) else (
Tools\mp4box -add "%%~na.mp4"#video -add "%%~na.mp4"#audio -add "%%a":lang=ko:hdlr=sbtl "%%~na-new.mp4"
if errorlevel 1 echo %%~na.mp4 >> "%list%"
)
)
)
)
list 라는 변수에 "자막 통합에 실패한 파일 목록.txt" 문자열을 할당하라
현 위치에 확장자 SRT 파일이 존재하면 (
TEMP 폴더가 없다면 TEMP 폴더를 만들어라
모든 SRT 파일에 대하여 다음 반복문을 실행하라 (
만약 SRT 파일과 동일한 이름의 MP4 파일이 존재한다면 (
미디어인포 프로그램으로 MP4 파일의 정보를 TEMP 폴더의 TEMP1.TXT 파일로 저장하라
TEMP 폴더의 TEMP1.TXT 파일에서 Codec ID : tx3g 문구가 있는지 찾아봐라
만약 이 문구가 없다면 (
기존에 있던 MP4 파일에 자막만 통합하라
만약 자막 통합시 오류가 발생했다면 MP4 파일 이름을 LIST 파일에 저장하라
) 만약 이 문구가 있다면 (
기존 MP4 파일에서 영상과 음성을 추출하고 자막을 통합하여 새로운 MP4 파일을 만들라
만약 자막 통합시 오류가 발생했다면 MP4 파일 이름을 LIST 파일에 저장하라
)
)
)
)
말로 설명하려니 좀 지저분한데 아무튼 위 예제에는 IF, IF NOT, IF EXIST, IF ERRORLEVEL, ELSE 모두 다 적절히 잘 활용되어 있습니다.
한가지 예를 더 들어보겠습니다. 한글, 영어, 통합 자막 이렇게 3가지 자막을 통합하려 한다면 경우의 수는 8가지가 나오겠지요. 그런데 한글 자막은 무조건 존재하고, 통합한다고 가정하면 4가지 경우가 발생합니다.
if exist 한글 (
if exist 영어 (
if exist 통합 (
한글, 영어, 통합 모두 있는 경우 명령어
) else (
한글, 영어만 있는 경우 명령어
)
) else (
if exist 통합 (
한글, 통합만 있는 경우 명령어
) else (
한글만 있는 경우 명령어
)
)
)
이정도면 IF 구문에 대해서는 충분히 설명을 했다고 생각되는데 어떠실지 모르겠네요. 프로그램을 작성하는 데 있어서 가장 중요한 것은 역시 논리적 사고라 생각합니다. 일단 논리적으로 설계도만 잘 짜면 코딩은 껍데기에 불과하다고 봅니다. 위 예는 아주 간단한 배치파일에 불과하지만 엄청 큰 규모의 프로그램을 작성하려면 설계도부터 체계적으로 잘 짜야겠지요.
FOR 구문은 여기서 따로 다루지 않겠습니다. 지난번에 작성했던 글을 참조하세요.
2010/08/28 - [윈도우 일반] - FOR 구문 기초 사용법
Perl 스크립트에는 FOR, FOREACH, WHILE 반복문이 있던데, 배치파일에는 FOR 반복문밖에 없고 사용법도 조금 제한적이라 아쉽기는 합니다. 하지만 그래도 저는 FOR 구문이 배치파일의 꽃중의 꽃이라 생각합니다. 꼭 잘 익혀두셔서 능숙하게 다루실 수 있기를 빌겠습니다.
SET에 대해서는 사실 프로그래밍 언어를 좀 알아야 개념을 이해하는데 도움이 되는데, 뭐 저도 프로그래밍 언어는 모르니까 딱 제가 이해하는 수준 정도로만 설명을 드리겠습니다.
SET 변수=문자열
일단 이게 기본입니다. 왼쪽에는 변수 이름을 적어주고 오른쪽에는 변수의 값을 적어줍니다. 그리고 배치파일에서 변수를 호출할 때는 양쪽에 %를 붙여주시면 됩니다.
예제)
set A=snoopy
echo %A%
위 예제를 실행하면 화면에 snoopy를 출력해줍니다. A 라는 변수에 snoopy라는 문자열이 값으로 지정되었기 때문입니다. 이때 변수는 대문자와 소문자를 구분합니다. 즉 A와 a는 다른 변수입니다.
SET /A 변수=수식
변수에 숫자를 할당할 때는 그냥 할당하면 되지만, 수식의 계산 결과를 할당하려면 /A 옵션을 붙여야 합니다.
예제)
set B=5
set /a B=B+3
echo %B%
위 예제의 결과값은 8이 나오겠지요? 참고로 연산식은 아래와 같이 좀 더 간단히 표현할 수 있는데
= *= /= %= += -= - 할당
예를 들어 위에 있는 set /a B=B+3 대신에 set /a B+=3 이렇게도 쓸 수 있습니다.
좀 더 예를 들어 설명드리는게 이해가 쉽겠네요.
B는 5라고 가정하고 아래 예제는 각각
set /a B+=3 => B에 3을 더해서 새로운 B 값을 할당 => 8
set /a B-=3 => B에 3을 빼서 새로운 B 값을 할당 => 2
set /a B*=3 => B에 3을 곱해서 새로운 B 값을 할당 => 15
set /a B/=3 => B를 3으로 나눈 몫을 새로운 B 값에 할당 => 1
set /a B%=3 => B를 3으로 나눈 나머지를 새로운 B 값에 할당 => 2
아래 예제의 결과물을 예측해보세요.
예제)
set i=0
for /l %%a in (1,1,100) do (
set /a i += %%a
)
echo %i%
pause
exit
정답은
다음은 메뉴 고르기에 많이 사용되는 SET /P 구문입니다. /p를 붙이면 프롬프트 상에서 사용자에게 입력값을 받는데요, C 언어의 scanf 함수와 비슷하다 볼 수 있습니다. 다음 예제를 배치파일로 실행해보면 이해가 바로 될 겁니다.
예제)
@echo off
set /p age=당신의 나이를 입력해주세요 :
echo 당신의 나이는 %age% 입니다.
pause
exit
변수 확장에 관한 이야기도 있는데 이건 제가 별로 사용하지 않아서... 대략 예를 하나만 들어보겠습니다.
예제)
@echo off
set snoopy=스누피는 컴퓨터를 좋아합니다.
set snoopy=%snoopy:~-10%
echo %snoopy%
위 예제를 실행하면 "퓨터를 좋아합니다." 문자만 출력됩니다. ~-10 이게 "뒤에서 10개의 문자만" 추출하는건데 아무튼 이 확장에 대해서는 그냥 각자 도움말을 참조하여 공부하세요.
이놈은 위 SET 명령어와 같이 활용해야 하는데 저는 잘 쓰지 않습니다. 그런데 이게 필요한 경우가 있습니다. 그것은 바로
SETLOCAL ENABLEDELAYEDEXPANSION
이녀석은 제가 가끔 FOR 구문에서 사용하는데 사실 저도 100% 완벽히 이해한 것은 아닙니다. 일단 아래 예를 한번 보세요.
예제)
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 (
set b=%%a
echo %b%
)
얼핏 생각하기에 위 예제는 작동할 것 같은데요, 사실은 작동하지 않습니다. 첫 명령어에서 b 변수에 C: 문자열이 할당되니까 C: 를 출력해주고, 그 다음엔 다시 b에 D: 문자열이 할당되어서 D: 문자열을 출력해주고... 이걸 Z: 출력까지 반복할 것 같지만 이상하게도 위 구문은 실행되지 않습니다.
위 예제가 의도대로 구동되도록 하려면 아래와 같이 바꿔야 합니다.
SETLOCAL ENABLEDELAYEDEXPANSION
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 (
set b=%%a
echo !b!
)
그러니까 SETLOCAL ENABLEDELAYEDEXPANSION을 설정한 다음 %b% 대신 !b!를 사용해야 합니다. 자세한 개념은 저도 설명을 못 하니 그냥 그렇다고만 알아두세요. 제가 대충 이해하기로는 이렇습니다. 저렇게 FOR 이나 IF에서 괄호를 사용해 아래쪽에 명령줄을 여러개 써넣어도 사실은 이게 한줄짜리 명령어인데, 명령어를 읽어들이는 과정과 명령어를 실행하는 과정 사이에 발생하는 시차 때문에 이런 문제가 생깁니다. b라는 변수에는 아무런 값도 할당되지 않은 상태인데 그상태로 명령어가 입력되기 때문에, 저 반복문에서는 "echo 설정되어있지 않은 변수" 이걸 반복하게 되는거죠. set으로 %%a 값을 b에 넣어주는건 시간적으로 그 다음에 일어나는 일이구요. 그래서 SETLOCAL ENABLEDELAYEDEXPANSION 옵션이 존재합니다. 아무튼 % 대신 ! 쓴다는거 알아두세요.
이것도 많이 쓰이는데 사용법이 어렵지 않아서 간단히 다룹니다. GOTO 뒤에는 레이블을 적어주시면 그리로 이동하는데 레이블은 콜론으로 시작합니다.
예제)
:menu
cls
echo.
echo 1. 저는 남자입니다.
echo 2. 저는 여자입니다.
echo.
set /p menu= 번호를 선택해주세요 :
if "%menu%"=="1" goto male
if "%menu%"=="2" goto female
goto menu
:male
cls
echo.
echo 당신은 남자입니다.
echo.
pause
exit
:female
cls
echo.
echo 당신은 여자입니다.
echo.
pause
exit
위 예에서 set /p menu 값에 1을 입력하면 male 부분으로 이동하고 2를 입력하면 female 부분으로 이동합니다. 1,2가 아닌 엉뚱한 값을 입력하면 menu 부분으로 다시 이동합니다. GOTO는 어렵지 않죠?
그리고 제가 exit를 썼는데 :EOF를 쓰기도 합니다. GOTO :EOF라고 적어주면 exit와 같은 효과를 얻을 수 있습니다. 따로 :EOF 레이블을 만들어줄 필요는 없습니다.
지금까지 지루한 내용을 꾹 참고 다 읽어오신 분이라면 (FOR 구문까지) 이제 웬만한 배치파일은 작성하실 수 있을 것 같은데, 그래도 이게 눈으로 보는 것과 직접 실습하는 것은 많이 다릅니다. 컴퓨터 뿐 아니라 공부나 다른 일도 마찬가지인데, 직접 몸으로 느껴봐야 진짜 나만의 지식이 될 수 있습니다.
일단 이 글을 작성한 이유가 고스트 자동 복구 DVD 만들기 글에서 배치파일 소스를 알려달라는 분들이 많았기 때문인데요, 저 글에 나온 배치파일은 이 글에서 설명한 어려운 구문들이 거의 들어가지 않습니다. 정말 쉽고 간단한 구문으로만 이루어져 있습니다. 그런데 당시 작성했던 스크립트를 다 쓰려면 좀 길어지기 때문에 메뉴를 단순화 해서 4가지만 적어보겠습니다.
어떤가요? 이 글에서 설명한 복잡한 내용은 하나도 없고 완전 단순하죠? 위 예제를 응용해서 나만의 고스트 자동 복구 DVD를 만드시면 되겠습니다.
혹시 잘못된 내용 있으면 고수님들 지적 부탁드립니다. ^^
도움말 활용하기
일단 잘 모르는 명령어가 있다면 도움말을 통해 기능을 익혀야겠지요. 사실 저는 이 배치파일을 거의 도움말을 통해 혼자서 익혔습니다. 예전에 어떤 분이 댓글로 저보고 배치파일을 진짜 잘 짠다고 하셨는데, 저도 어차피 도움말 보면서 익힌 것이니까 누구든지 도움말을 잘 이해하면 충분히 훌륭한 배치파일을 만들 수 있다고 생각합니다. 그런데 경우에 따라 도움말이 별로 친절하지 않을 수도 있습니다. 하지만 처음에는 이해되지 않던 말들도 시간이 지나고 경험이 쌓이면 나중에 다시 봤을 때 이해되는 경우가 많습니다. 예전에는 제가 FOR 구문의 대체 변수 참조 확장을 잘 이해하지 못했는데, 최근에는 잘 이해하게 되었습니다. 여러분도 이 도움말을 적극적으로 활용해보세요.
일반적으로 해당 명령어 뒤에 /? 를 붙이면 도움말이 나옵니다. 예를 들어 FOR 반복문의 사용법이 궁금하다면 FOR /? 해보면 되겠지요. 또는 HELP FOR 하셔도 동일한 결과를 얻을 수 있습니다. 그런데 도움말이 길면 스크롤 압박이 있으니 이 경우 도움말을 텍스트 파일로 저장해서 보셔도 되겠습니다. 뒤에 > 파일.txt 적어주시면 출력 결과를 텍스트 파일로 저장해줍니다.
예제)
FOR /? > "FOR 사용법.TXT"
ECHO
ECHO는 글자 그대로 메아리를 뜻하는데, 화면에 메시지를 그대로 출력해줍니다. 배치파일에선 사용자에게 뭔가 설명해줘야 하는 부분이 많은데 이럴 때 ECHO를 활용합니다. 주로 SET, IF, GOTO 등과 결합해서 메뉴를 보여줄 때 많이 사용하지요.
예제)
ECHO 저는 에코입니다. 화면에 메시지를 보여주기 위해 사용되지요.
그런데 보통 배치파일 첫 줄에는 @ECHO OFF를 많이 적어줍니다. 만약 @ECHO OFF를 적어주지 않으면 각 명령줄을 화면에 그대로 한번 출력을 해주고 실행을 하기 때문에 화면이 많이 지저분해집니다. 그래서 보통은 배치파일의 첫 줄에서 ECHO를 OFF 시켜줍니다.
이 ECHO 명령어 역시 출력 결과를 텍스트파일로 저장할 수 있습니다. (리디렉션은 거의 모든 경우에 사용할 수 있습니다.) 예를 들어 DISKPART를 사용하는 경우 배치파일에선 DISKPART 다음줄부터 작동하지 않는데요, 이럴 때는 DISKPART 다음줄부터 사용될 명령어를 스크립트로 저장한 다음 DISKPART /S 스크립트 이렇게 사용해야 합니다.
예제)
@echo off
pushd %~dp0
echo create vdisk file=d:\test.vhd type=expandable maximum=20480 > test.txt
echo attach vdisk >> test.txt
echo create partition primary >> test.txt
echo format quick fs=ntfs >> test.txt
echo assign letter >> test.txt
echo exit >> test.txt
diskpart /s test.txt
exit
위 예제가 무슨 소린지 아직은 잘 이해되지 않을 수도 있는데, 아무튼 echo와 리디렉션을 활용하여 텍스트파일로 출력하는게 가능하기 때문에 배치파일 안에서 이렇게 새로운 배치파일이나 스크립트를 echo만을 사용하여 작성할 수 있습니다. 위 예제는 윈도우 7에서 D 드라이브에 TEST.VHD 파일을 자동으로 생성하는 기능을 합니다.
※ ESCAPE 문자
제가 한가지 빠트려서 보충합니다. echo로 리디렉션을 할때 만약에 >> 기호 역시도 echo의 일부분으로 포함시키고 싶다면 어떻게 해야 할까요? 예를 들어
echo dir /b >> list.txt >> test.txt
위 구문을 실행하면 test.txt에 dir /b 부분만 들어갑니다. 넣고싶은 문자열은 dir /b >> list.txt 인데 말이죠. 이런 경우 앞서 나온 >> 문자열을 리디렉션이 아니라고 Escape 시킬 필요가 있습니다. 이때는 caret 문자 ^ 를 붙여주면 됩니다. 그러니까 위 예제를 결과값이 의도대로 나오게 고치려면
echo dir /b ^>^> list.txt >> test.txt
PUSHD %~DP0
이것 역시 제가 배치파일 초반에 항상 적어주는데요, 그 이유는 윈도우 7 때문입니다. 윈도우 7에선 특이하게도 UAC가 켜져있는 환경에서 배치파일을 관리자 권한으로 실행하는 경우 명령 프롬프트 위치가 C:\Windows\System32 기준으로 실행됩니다. 이게 왜 문제가 되냐하면 보통은 배치파일과 함께 같은 위치에 첨부 파일을 두고 다른 곳으로 복사해주는 명령어를 쓰거나 아니면 그 첨부파일을 실행하는 경우가 많은데, 이렇게 명령 프롬프트 위치가 변경되어 버리면 복사할 파일이나 실행할 파일의 절대경로를 적어야 합니다. 그런데 배치파일은 어느 위치에서 실행될지 아무도 모르죠. 따라서 복사할 파일의 절대경로도 그때그때 달라지게 됩니다. 물론 각 파일 경로 앞에 %~DP0를 일일이 붙여주면 되지만 그건 너무 귀찮은 일입니다. 따라서 이렇게 명령 프롬프트 위치를 배치파일이 있는 디렉터리로 되돌려주는게 훨씬 편합니다.
그런데 %~DP0의 의미가 궁금하실 것 같습니다. 이게 바로 FOR 구문의 대체 변수 참조 확장입니다. 자세한 내용은 FOR /? 입력해서 확인해보시구요, 저는 간단히 예제를 통해 설명드리겠습니다.
배치파일에서 %0는 그 배치파일의 전체 경로를 지칭합니다. %0 사이에 들어있는 ~dp는 %변수를 드라이브 문자와 경로로만 확장해줍니다. 예를 들어 제 컴퓨터 바탕화면에 예제.cmd 파일이 있는 경우
%0 |
“C:\Users\snoopy\Desktop\예제.cmd” |
%~0 |
C:\Users\snoopy\Desktop\예제.cmd |
%~d0 |
C: |
%~p0 |
\Users\snoopy\Desktop\ |
%~n0 |
예제 |
%~x0 |
.cmd |
%~dp0 |
C:\Users\snoopy\Desktop\ |
따라서 pushd %~dp0 라고 적으면 명령 프롬프트가 배치파일이 존재하는 위치로 돌아오게 됩니다. 이제 응용력이 뛰어나신 분들은 이런 생각을 하실 것 같습니다. "그렇다면 %~dpnx0 와 %~0 는 같은 값을 나타내겠군!" 네 그렇습니다. %~ 확장은 이처럼 한꺼번에 섞어서 사용해도 됩니다.
※ 참고로 PUSHD %~DP0 대신에 CD /D %~DP0 해도 상관은 없습니다.
TITLE
이건 별로 중요하지 않은데, 배치파일을 실행했을 때 콘솔창에 표시되는 창 제목을 지정합니다. 원래 아무것도 지정하지 않으면 제목이 C:\Windows\System32\cmd.exe 인데, 이 부분을 변경하는 것입니다.
예제)
title 아이폰 4 AVI, MKV 동영상 자동 변환기
MODE
이것도 별로 중요하지는 않은데, 배치파일에선 콘솔창 크기를 지정하는 용도로 사용할 수 있습니다.
예제)
mode con cols=40 lines=11
COLOR
콘솔창의 화면 색을 지정할 수 있습니다. 저는 까만 바탕에 흰 글씨가 마음에 들지만 예를 들어 파란 바탕에 흰 글씨로 지정할 수도 있겠지요.
0 = 검정색 8 = 회색
1 = 파랑색 9 = 연한 파랑색
2 = 초록색 A = 연한 초록색
3 = 옥색 B = 연한 옥색
4 = 빨강색 C = 연한 빨강색
5 = 자주색 D = 연한 자주색
6 = 노랑색 E = 연한 노랑색
7 = 흰색 F = 밝은 흰색
첫째 자리는 배경색이고 둘째 자리는 문자색입니다.
예제)
color 1F
CLS
화면을 깨끗하게 비웁니다. Clear Screen의 약자인데 보통 새로 메뉴를 출력해주는 경우 기존에 보이던 결과물 때문에 지저분하니까 CLS를 적어줍니다.
PAUSE
이것도 주로 안내문을 보여준 다음 적어줍니다. 일시정지 시켜둬야 사람들이 안내문을 읽어볼 수 있으니까요. 아무 키나 누르면 다음 명령어로 넘어갑니다. 저는 보통 배치파일을 작성하면서 중간중간에 PAUSE를 걸어넣고 파일을 실행해봅니다. 여기까지 오류없이 잘 작성되었는지 테스트 해보기 위함이죠.
IF, IF NOT, IF EXIST, IF ERRORLEVEL, ELSE
지금부터가 진짜 배치파일입니다. 위에서 다뤘던 내용들은 그냥 준비운동 정도였고 배치파일에서 가장 많이 사용되는 (저만 가장 많이 사용하는지도 모르지만 ;;;) 구문이 바로 IF, FOR, SET 입니다. 이 3가지 구문이 배치파일의 꽃이라고 저는 생각합니다. 특히 저는 FOR 반복문을 매우 자주 사용하는 편인데, FOR 구문을 잘 활용하시면 "감히 배치파일로 이게 가능한가?" 생각했던 기능들도 훌륭히 만들어낼 수 있습니다.
IF는 말 그대로 "~인지 아닌지" 를 판단합니다. 만약 조건이 참이면 그 뒤에 나오는 명령어를 수행하고 참이 아니면 다음 줄로 넘어갑니다.
IF 문자열1==문자열2 명령어
예제)
set A=snoopy
if %A%==snoopy echo %A%는 snoopy와 같습니다.
set B=snoopybox
if %B%==snoopy echo %B%는 snoopy와 같습니다.
위 예제에서 첫번째 IF 구문은 조건이 참이기 때문에 "snoopy는 snoopy와 같습니다." 문구를 출력해줍니다. 하지만 두번째 IF 구문은 조건이 거짓이기 때문에 그 뒤에 나오는 echo 명령어는 무시됩니다.
IF 뒤에 /i 를 붙이시면 대소문자를 구분하지 않습니다. 이게 윈도우에선 IF 도움말에 잘못 표기되어 있네요. /i를 붙이면 대소문자 구분이 없고, 안 붙이면 대소문자를 구분합니다. 도움말에는 반대로 나와 있습니다.
숫자 비교에는 아래 비교연산자들이 사용됩니다.
EQU - 같음
NEQ - 같지 않음
LSS - 보다 작은
LEQ - 작거나 같음
GTR - 보다 큰
GEQ - 크거나 같음
예제)
if 5 equ 5 echo 5는 5와 같습니다.
if 5 neq 5 echo 5는 5와 같지 않습니다.
if 5 lss 5 echo 5는 5보다 작습니다.
if 5 leq 5 echo 5는 5보다 작거나 같습니다.
if 5 gtr 5 echo 5는 5보다 큽니다.
if 5 geq 5 echo 5는 5보다 크거나 같습니다.
위 예제에서는 1, 4, 6번째 줄만 참이기 때문에 뒤에 있는 echo가 출력되겠지요? 대충 저렇게 쓴다는 것만 알고 다음으로 넘어갑니다.
IF NOT은 IF와 반대로 생각하면 됩니다. 뒤에 나온 조건이 거짓인 경우에 IF NOT은 참이 되기 때문에 명령을 실행하게 됩니다.
예제)
if not snoopy==snoopy echo 과연 이 메시지가 출력될까?
위 예제를 실행하면 echo 다음에 나오는 메시지가 출력되지 않습니다. IF NOT이니까요. 하지만 만약에 if not snoopy==snoopybox 했다면 뒤에 나오는 명령어는 출력이 되었겠지요?
IF EXIST는 지정한 파일, 폴더가 존재하면 조건을 참으로 받아줍니다. 대략 아래와 같은 예를 만들어 보겠습니다.
예제)
if exist %windir%\syswow64 echo 이 윈도우는 64비트입니다.
if not exist %windir%\syswow64 echo 이 윈도우는 64비트가 아닙니다.
위 예제를 실행하면 64비트 윈도우인 경우 첫번째 echo 구문만 출력될 것이고, 32비트 윈도우인 경우 두번째 echo 구문만 출력될 것입니다. 마찬가지로 IF EXIST 구문도 IF NOT EXIST로 활용할 수 있습니다.
IF ERRORLEVEL 역시 제가 자주 사용하는 구문인데 마지막으로 실행된 프로그램의 종료코드가 무엇인지를 가지고 조건을 판단합니다. 일반적으로 아무런 오류가 없이 잘 실행된 경우에는 종료코드가 0입니다. 오류가 발생하면 종료코드는 1 이상입니다. IF ERRORLEVEL 1 하시면 종료코드가 1보다 크거나 같은 경우 참으로 인식합니다.
예제)
ren C:\Windows WindowsXP
if errorlevel 1 echo 윈도우 폴더는 이름을 변경할 수 없어요.
위 예제에서 첫번째 줄에 Windows 폴더 이름을 WindowsXP로 변경하라고 합니다. 말이 안 되죠? 당연히 오류가 발생할 수 밖에 없습니다. 따라서 두번째 줄에 있는 IF ERRORLEVEL 1 구문은 바로 위에서 오류가 발생했기 때문에 값이 참으로 지정되어 echo 뒤에 나오는 문구를 출력해줍니다.
ELSE는 IF랑 묶어서 사용하는데 여기서부터는 괄호를 사용하겠습니다. 이 괄호를 보기좋게 잘 써야 프로그램을 체계적으로 짤 수 있고, 나중에 자기가 봐도 흐름이 한 눈에 보입니다. 위에서 예를 들었던 윈도우 64비트 판별을 ELSE로 표현해보자면
예제)
if exist %windir%\syswow64 (
echo 이 윈도우는 64비트입니다.
) else (
echo 이 윈도우는 64비트가 아닙니다.
)
그러니까 ELSE는 IF 조건이 거짓인 경우 실행됩니다. IF가 옳으면 IF 구문 뒤에 있는 명령어가 실행되고, 그게 아니면 ELSE 뒤에 있는 명령어가 실행됩니다. 둘중에 하나만 무조건 실행되게 만드는 양자택일 구문이라 보시면 됩니다.
여기까지 대충 IF 구문에 대해 알아봤는데요 실전 예제 몇가지를 소개해봅니다. 아래는 제가 아이폰 4 AVI, MKV 동영상을 MP4로 한방에 변환하기 글에서 사용한 SRT 자막 통합 스크립트입니다.
예제)
set list=자막 통합에 실패한 파일 목록.txt
if exist *.srt (
if not exist temp md temp
for %%a in (*.srt) do (
if exist "%%~na.mp4" (
Tools\mediainfo "%%~na.mp4" > temp\temp1.txt
findstr /c:"Codec ID : tx3g" temp\temp1.txt > nul
if errorlevel 1 (
Tools\mp4box -add "%%a":lang=ko:hdlr=sbtl "%%~na.mp4"
if errorlevel 1 echo %%~na.mp4 >> "%list%"
) else (
Tools\mp4box -add "%%~na.mp4"#video -add "%%~na.mp4"#audio -add "%%a":lang=ko:hdlr=sbtl "%%~na-new.mp4"
if errorlevel 1 echo %%~na.mp4 >> "%list%"
)
)
)
)
list 라는 변수에 "자막 통합에 실패한 파일 목록.txt" 문자열을 할당하라
현 위치에 확장자 SRT 파일이 존재하면 (
TEMP 폴더가 없다면 TEMP 폴더를 만들어라
모든 SRT 파일에 대하여 다음 반복문을 실행하라 (
만약 SRT 파일과 동일한 이름의 MP4 파일이 존재한다면 (
미디어인포 프로그램으로 MP4 파일의 정보를 TEMP 폴더의 TEMP1.TXT 파일로 저장하라
TEMP 폴더의 TEMP1.TXT 파일에서 Codec ID : tx3g 문구가 있는지 찾아봐라
만약 이 문구가 없다면 (
기존에 있던 MP4 파일에 자막만 통합하라
만약 자막 통합시 오류가 발생했다면 MP4 파일 이름을 LIST 파일에 저장하라
) 만약 이 문구가 있다면 (
기존 MP4 파일에서 영상과 음성을 추출하고 자막을 통합하여 새로운 MP4 파일을 만들라
만약 자막 통합시 오류가 발생했다면 MP4 파일 이름을 LIST 파일에 저장하라
)
)
)
)
말로 설명하려니 좀 지저분한데 아무튼 위 예제에는 IF, IF NOT, IF EXIST, IF ERRORLEVEL, ELSE 모두 다 적절히 잘 활용되어 있습니다.
한가지 예를 더 들어보겠습니다. 한글, 영어, 통합 자막 이렇게 3가지 자막을 통합하려 한다면 경우의 수는 8가지가 나오겠지요. 그런데 한글 자막은 무조건 존재하고, 통합한다고 가정하면 4가지 경우가 발생합니다.
한글 |
영어 |
통합 |
O |
O |
O |
O |
O |
X |
O |
X |
O |
O |
X |
X |
if exist 한글 (
if exist 영어 (
if exist 통합 (
한글, 영어, 통합 모두 있는 경우 명령어
) else (
한글, 영어만 있는 경우 명령어
)
) else (
if exist 통합 (
한글, 통합만 있는 경우 명령어
) else (
한글만 있는 경우 명령어
)
)
)
이정도면 IF 구문에 대해서는 충분히 설명을 했다고 생각되는데 어떠실지 모르겠네요. 프로그램을 작성하는 데 있어서 가장 중요한 것은 역시 논리적 사고라 생각합니다. 일단 논리적으로 설계도만 잘 짜면 코딩은 껍데기에 불과하다고 봅니다. 위 예는 아주 간단한 배치파일에 불과하지만 엄청 큰 규모의 프로그램을 작성하려면 설계도부터 체계적으로 잘 짜야겠지요.
FOR
FOR 구문은 여기서 따로 다루지 않겠습니다. 지난번에 작성했던 글을 참조하세요.
2010/08/28 - [윈도우 일반] - FOR 구문 기초 사용법
Perl 스크립트에는 FOR, FOREACH, WHILE 반복문이 있던데, 배치파일에는 FOR 반복문밖에 없고 사용법도 조금 제한적이라 아쉽기는 합니다. 하지만 그래도 저는 FOR 구문이 배치파일의 꽃중의 꽃이라 생각합니다. 꼭 잘 익혀두셔서 능숙하게 다루실 수 있기를 빌겠습니다.
SET
SET에 대해서는 사실 프로그래밍 언어를 좀 알아야 개념을 이해하는데 도움이 되는데, 뭐 저도 프로그래밍 언어는 모르니까 딱 제가 이해하는 수준 정도로만 설명을 드리겠습니다.
SET 변수=문자열
일단 이게 기본입니다. 왼쪽에는 변수 이름을 적어주고 오른쪽에는 변수의 값을 적어줍니다. 그리고 배치파일에서 변수를 호출할 때는 양쪽에 %를 붙여주시면 됩니다.
예제)
set A=snoopy
echo %A%
위 예제를 실행하면 화면에 snoopy를 출력해줍니다. A 라는 변수에 snoopy라는 문자열이 값으로 지정되었기 때문입니다. 이때 변수는 대문자와 소문자를 구분합니다. 즉 A와 a는 다른 변수입니다.
SET /A 변수=수식
변수에 숫자를 할당할 때는 그냥 할당하면 되지만, 수식의 계산 결과를 할당하려면 /A 옵션을 붙여야 합니다.
예제)
set B=5
set /a B=B+3
echo %B%
위 예제의 결과값은 8이 나오겠지요? 참고로 연산식은 아래와 같이 좀 더 간단히 표현할 수 있는데
= *= /= %= += -= - 할당
예를 들어 위에 있는 set /a B=B+3 대신에 set /a B+=3 이렇게도 쓸 수 있습니다.
좀 더 예를 들어 설명드리는게 이해가 쉽겠네요.
B는 5라고 가정하고 아래 예제는 각각
set /a B+=3 => B에 3을 더해서 새로운 B 값을 할당 => 8
set /a B-=3 => B에 3을 빼서 새로운 B 값을 할당 => 2
set /a B*=3 => B에 3을 곱해서 새로운 B 값을 할당 => 15
set /a B/=3 => B를 3으로 나눈 몫을 새로운 B 값에 할당 => 1
set /a B%=3 => B를 3으로 나눈 나머지를 새로운 B 값에 할당 => 2
아래 예제의 결과물을 예측해보세요.
예제)
set i=0
for /l %%a in (1,1,100) do (
set /a i += %%a
)
echo %i%
pause
exit
정답은
다음은 메뉴 고르기에 많이 사용되는 SET /P 구문입니다. /p를 붙이면 프롬프트 상에서 사용자에게 입력값을 받는데요, C 언어의 scanf 함수와 비슷하다 볼 수 있습니다. 다음 예제를 배치파일로 실행해보면 이해가 바로 될 겁니다.
예제)
@echo off
set /p age=당신의 나이를 입력해주세요 :
echo 당신의 나이는 %age% 입니다.
pause
exit
변수 확장에 관한 이야기도 있는데 이건 제가 별로 사용하지 않아서... 대략 예를 하나만 들어보겠습니다.
예제)
@echo off
set snoopy=스누피는 컴퓨터를 좋아합니다.
set snoopy=%snoopy:~-10%
echo %snoopy%
위 예제를 실행하면 "퓨터를 좋아합니다." 문자만 출력됩니다. ~-10 이게 "뒤에서 10개의 문자만" 추출하는건데 아무튼 이 확장에 대해서는 그냥 각자 도움말을 참조하여 공부하세요.
SETLOCAL
이놈은 위 SET 명령어와 같이 활용해야 하는데 저는 잘 쓰지 않습니다. 그런데 이게 필요한 경우가 있습니다. 그것은 바로
SETLOCAL ENABLEDELAYEDEXPANSION
이녀석은 제가 가끔 FOR 구문에서 사용하는데 사실 저도 100% 완벽히 이해한 것은 아닙니다. 일단 아래 예를 한번 보세요.
예제)
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 (
set b=%%a
echo %b%
)
얼핏 생각하기에 위 예제는 작동할 것 같은데요, 사실은 작동하지 않습니다. 첫 명령어에서 b 변수에 C: 문자열이 할당되니까 C: 를 출력해주고, 그 다음엔 다시 b에 D: 문자열이 할당되어서 D: 문자열을 출력해주고... 이걸 Z: 출력까지 반복할 것 같지만 이상하게도 위 구문은 실행되지 않습니다.
위 예제가 의도대로 구동되도록 하려면 아래와 같이 바꿔야 합니다.
SETLOCAL ENABLEDELAYEDEXPANSION
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 (
set b=%%a
echo !b!
)
그러니까 SETLOCAL ENABLEDELAYEDEXPANSION을 설정한 다음 %b% 대신 !b!를 사용해야 합니다. 자세한 개념은 저도 설명을 못 하니 그냥 그렇다고만 알아두세요. 제가 대충 이해하기로는 이렇습니다. 저렇게 FOR 이나 IF에서 괄호를 사용해 아래쪽에 명령줄을 여러개 써넣어도 사실은 이게 한줄짜리 명령어인데, 명령어를 읽어들이는 과정과 명령어를 실행하는 과정 사이에 발생하는 시차 때문에 이런 문제가 생깁니다. b라는 변수에는 아무런 값도 할당되지 않은 상태인데 그상태로 명령어가 입력되기 때문에, 저 반복문에서는 "echo 설정되어있지 않은 변수" 이걸 반복하게 되는거죠. set으로 %%a 값을 b에 넣어주는건 시간적으로 그 다음에 일어나는 일이구요. 그래서 SETLOCAL ENABLEDELAYEDEXPANSION 옵션이 존재합니다. 아무튼 % 대신 ! 쓴다는거 알아두세요.
GOTO
이것도 많이 쓰이는데 사용법이 어렵지 않아서 간단히 다룹니다. GOTO 뒤에는 레이블을 적어주시면 그리로 이동하는데 레이블은 콜론으로 시작합니다.
예제)
:menu
cls
echo.
echo 1. 저는 남자입니다.
echo 2. 저는 여자입니다.
echo.
set /p menu= 번호를 선택해주세요 :
if "%menu%"=="1" goto male
if "%menu%"=="2" goto female
goto menu
:male
cls
echo.
echo 당신은 남자입니다.
echo.
pause
exit
:female
cls
echo.
echo 당신은 여자입니다.
echo.
pause
exit
위 예에서 set /p menu 값에 1을 입력하면 male 부분으로 이동하고 2를 입력하면 female 부분으로 이동합니다. 1,2가 아닌 엉뚱한 값을 입력하면 menu 부분으로 다시 이동합니다. GOTO는 어렵지 않죠?
그리고 제가 exit를 썼는데 :EOF를 쓰기도 합니다. GOTO :EOF라고 적어주면 exit와 같은 효과를 얻을 수 있습니다. 따로 :EOF 레이블을 만들어줄 필요는 없습니다.
실전 예제 고스트 자동 복구 DVD
지금까지 지루한 내용을 꾹 참고 다 읽어오신 분이라면 (FOR 구문까지) 이제 웬만한 배치파일은 작성하실 수 있을 것 같은데, 그래도 이게 눈으로 보는 것과 직접 실습하는 것은 많이 다릅니다. 컴퓨터 뿐 아니라 공부나 다른 일도 마찬가지인데, 직접 몸으로 느껴봐야 진짜 나만의 지식이 될 수 있습니다.
일단 이 글을 작성한 이유가 고스트 자동 복구 DVD 만들기 글에서 배치파일 소스를 알려달라는 분들이 많았기 때문인데요, 저 글에 나온 배치파일은 이 글에서 설명한 어려운 구문들이 거의 들어가지 않습니다. 정말 쉽고 간단한 구문으로만 이루어져 있습니다. 그런데 당시 작성했던 스크립트를 다 쓰려면 좀 길어지기 때문에 메뉴를 단순화 해서 4가지만 적어보겠습니다.
@echo off
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\sources\backup.gho set DVD=%%a
)
:_main
cls
echo.
echo.
echo.
echo 1. 고스트 수동으로 작업하기
echo.
echo 2. 첫번째 하드의 첫번째 파티션에 복원하기
echo.
echo 3. 명령 프롬프트 띄우기
echo.
echo 4. 파티션 위저드 실행하기
echo.
echo.
echo.
set /p menu=번호를 입력해주세요 :
if "%menu%"=="1" goto _ghost
if "%menu%"=="2" goto _restore
if "%menu%"=="3" goto _cmd
if "%menu%"=="4" goto _pwhe
goto _main
:_ghost
X:\ghost32
goto _main
:_restore
X:\ghost32 -clone,mode=pload,src=%DVD%\sources\backup.gho:1,dst=1:1 -auto -sure -rb -noide -fnf
exit
:_cmd
start cmd
goto _main
:_pwhe
X:\pwhe
goto _main
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\sources\backup.gho set DVD=%%a
)
:_main
cls
echo.
echo.
echo.
echo 1. 고스트 수동으로 작업하기
echo.
echo 2. 첫번째 하드의 첫번째 파티션에 복원하기
echo.
echo 3. 명령 프롬프트 띄우기
echo.
echo 4. 파티션 위저드 실행하기
echo.
echo.
echo.
set /p menu=번호를 입력해주세요 :
if "%menu%"=="1" goto _ghost
if "%menu%"=="2" goto _restore
if "%menu%"=="3" goto _cmd
if "%menu%"=="4" goto _pwhe
goto _main
:_ghost
X:\ghost32
goto _main
:_restore
X:\ghost32 -clone,mode=pload,src=%DVD%\sources\backup.gho:1,dst=1:1 -auto -sure -rb -noide -fnf
exit
:_cmd
start cmd
goto _main
:_pwhe
X:\pwhe
goto _main
어떤가요? 이 글에서 설명한 복잡한 내용은 하나도 없고 완전 단순하죠? 위 예제를 응용해서 나만의 고스트 자동 복구 DVD를 만드시면 되겠습니다.
혹시 잘못된 내용 있으면 고수님들 지적 부탁드립니다. ^^
'윈도우 일반' 카테고리의 다른 글
로컬 그룹 정책 편집기를 레지스트리로 대체하기 (25) | 2010.10.19 |
---|---|
파일을 휴지통에 버리지 않고 바로 삭제하기 (26) | 2010.10.18 |
지정된 시각에 컴퓨터 자동종료 설정하기 (34) | 2010.10.17 |
하드디스크 드라이브 문자 강제로 변경하기 (52) | 2010.10.12 |
윈도우 시디키 확인 프로그램 (45) | 2010.08.31 |
NTFS로 포맷하면 사용 중인 공간이 생기는 이유 (16) | 2010.08.29 |
FOR 구문 기초 사용법 (15) | 2010.08.28 |
하드디스크에 윈도우가 설치되지 않는 경우 (35) | 2010.08.20 |
최근에 달린 댓글 최근에 달린 댓글