들어가며
IF ERRORLEVEL문은 방금 실행을 마친 프로그램의 종료코드(마침코드)를 비교하여 프로그램 수행을 결정하는 구문이다. 이를 위해 몇 가지 프로그램의 종료코드를 소개하고자 한다. 또한 이러한 종료코드는 ERRORLEVEL 환경변수(%ERRORLEVEL%)에 저장하여 이용할 수도 있다.
말뜻
종료코드(마침코드)는 프로그램이 수행 과정에서 어떻게 처리하였는지를 알려주는 정수를 가리킨다. 주로 정수 0은 정상 종료되었음을 뜻하면 1보다 크거나 같은 값은 오류가 발생했음을 뜻한다. 프로그램이 종료하면서 운영체제에 넘겨주기 때문에 종료코드라는 이름이 붙었다.
여러 프로그램의 종료코드
윈도XP의 도움말 및 지원 센터의 내용에 따르면 다음과 같은 종료코드를 가지고 있다고 한다.
-
diskcomp : 두 플로피디스크를 비교하는 명령어
- 0 : 두 플로피디스크가 같다. (정상 종료)
- 1 : 차이를 발견했다.
- 2 : 하드웨어 오류 발생.
- 3 : 초기화 오류 발생.
-
xcopy : 하위 디렉터리와 파일을 복사하는 명령어
- 0 : 파일이 오류 없이 복사됨. (정상 종료)
- 1 : 복사할 파일을 찾지 못하다.
- 2 : 사용자가 Ctrl+C를 눌러 강제 종료.
- 4 : 초기화 오류가 발생. 메모리나 디스크 공간 부족, 명령줄에 잘못된 드라이브 이름이나 잘못된 구문을 입력했을 때 생긴다.
- 5 : 디스크 쓰기 오류가 발생했습니다.
-
color : 전경색(글자색)과 배경색을 지정하고 복원하는 명령어
- 0 : 전경색과 배경색이 다르다.
- 1 : 전경색과 배경색이 같다.
-
diskcopy : 플로피디스크에서 다른 플로피디스크로 복사하는 명령어
- 0 : 복사 성공. (정상 종료)
- 1 : 치명적이지 않은 읽기/쓰기 오류가 발생
- 3 : 치명적인 하드웨어 오류가 발생
- 4 : 초기화 오류가 발생
-
format : 디스크를 초기화하는 명령어
- 0 : 포맷을 성공했습니다. (정상 종료)
- 1 : 잘못된 매개 변수를 입력
- 4 : 치명적인 오류가 발생 (0, 1 또는 5를 제외한 오류).
- 5 : "포맷을 실행하시겠습니까(Y/N)?" 메시지에서 N 키를 눌러 실행이 중단됨.
-
graftabl : 그래픽 모드에서 확장 문자 집합을 표시하는 기능을 사용 가능하게 설정합니다.
- 0 : 문자 집합을 기억장치에 읽어들이는 데 성공. 이전 코드 페이지는 로드되지 않는다. (정상 종료)
- 1 : 잘못된 매개 변수. 작업이 수행되지 않는다.
- 2 : 파일 오류가 발생
-
replace : 대상 디렉터리의 파일을 이름이 같은 원본 디렉터리의 파일로 바꾼다. replace를 사용하여 대상 디렉터리에 고유 파일 이름을 추가할 수도 있다.
- 0 : replace 명령이 성공적으로 파일을 바꾸거나 추가했습니다. (정상 종료)
- 1 : replace 명령이 맞지 않는 MS-DOS 버전을 발견했습니다.
- 2 : replace 명령이 원본 파일을 찾을 수 없습니다.
- 3 : replace 명령이 원본이나 대상 경로를 찾을 수 없습니다.
- 5 : 사용자는 바꾸고자 하는 파일을 액세스할 수 없습니다.
- 8 : 명령을 실행할 시스템 메모리가 부족합니다.
- 11 : 명령줄에 잘못된 구문을 사용했습니다.
-
그밖에 마이크로소프트 제품의 setup.exe 프로그램 : 윈도용 애플리케이션의 설치 프로그램
- 0 : 프로그램 설치를 성공 또는 사용자가 취소한 경우. (정상 종료)
- 0 이외의 값 : 프로그램 설치 도중에 프로그램 오류 발생
-
고스트 등의 시만텍 사의 프로그램
- 0 : 오류가 발생하지 않고 정상 종료
- 0 이외의 값 : 오류가 발생
예제 1
IF ERRORLEVEL문과 ELSE를 함께 사용한 예제는 GBackup1H2P.cmd 파일이다. 지난번에 작성한 GBackup1H2P.cmd을
GBackup1H2P-1.cmd로 이름을 바꾸어 저장하고, GBackup1H2P.cmd을 편집해 보자.
- GHOST.exe -CLONE,MODE=PDUMP,SRC=1:1,DST=1:2\GHOST.GHO -Z9 -AUTO -SURE -RB
- REM IF-ELSE 구문 : 오류가 발생하면 오류 발생을 알려준다.
- IF ERRORLEVEL 1 (
- ECHO ##############################################
- ECHO ## 백업 도중 오류가 발생했습니다. ##
- ECHO ##############################################
- ) ELSE (
- ECHO ##############################################
- ECHO ## 백업 작업을 정상적으로 마쳤습니다. ##
- ECHO ##############################################
- )
바뀐 부분만 나타내면 위와 같다. 이때 IF는 '('와 같은 명령줄에 있어야 하며, ')'와 ELSE가 같은 명령줄에 있어야 한다. 또한 ELSE는 뒤따르는 '('와 같은 명령줄에 있어야 한다.
- 참고 : 앞서 말했듯이 위 코드는 정상 작동하지 않는다. 다만 ERRORLEVEL 검사는 잘 된다.
예제 2
XCOPY를 이용한 백업 유틸리티를 제작해 보았다.
- @echo off
- rem 파일명 : Xback.bat
- rem 지은이 : koc2000/SALM
- rem 저작권 : GPL v3
- rem 예제 12.
- rem XCOPY를 이용한 백업
- rem 사용법 : Xback 원본디렉터리 대상디렉터리
- rem 작업 1 : 매개변수가 있는가? 없으면 도움말을 보여준다.
- IF NOT * == %2* (
- REM 매개변수가 모두 있으면 작업을 시작한다.
- REM XCOPY 명령을 이용해 백업합니다.
- XCOPY %1 %2 /i /S /E /H /M
- REM 종료코드가 4 또는 그보다 크면
- IF ERRORLEVEL 4 (
- echo 파일을 백업하기에는 메모리가 부족하거나
- echo 드라이브가 잘못 지정되었거나 명령줄 구문이 틀립니다.
- ) ELSE IF ERRORLEVEL 2 (
- echo 사용자가 CTRL+C를 눌러 백업 작업을 강제 종료했습니다.
- ) ELSE IF ERRORLEVEL 0 (
- echo 백업을 정상적으로 성공했습니다.
- )
- ) ELSE (
- REM 매개변수가 없으면 메시지를 보인 뒤 사용법을 보여준다.
- ECHO 매개변수가 없거나 모자랍니다.
- ECHO 구문 : Xback source_dir backup_dir
- )
- :END
위 구문에서 11행의 " IF NOT * == %2* ( " 부분은 문자열 비교문에서 다시 설명하기로 한다.
또한 위의 코드에서 ERRORLEVEL 값이 큰 값부터 차례대로 낮아지게 만드는 것이 배치파일에서는 묵시적 원칙입니다. 이는 실수로 일어날 수 있는 오류를 막기 위한 방법이지요. 왜냐하면 IF ERRORLEVEL 구문은 "같은 값"을 구하는 구문이 아니기 때문입니다.
- IF [NOT] ERRORLEVEL 정수 명령어
위와 같은 경우 정수보다 크거나 같으면 뒤따르는 명령어를 실행하게 되어 있습니다.
- IF ERRORLEVEL 1 command01
- IF ERRORLEVEL 2 command02
- IF ERRORLEVEL 3 command03
- IF ERRORLEVEL 4 command04
- IF ERRORLEVEL 15 command15
만약에 command01을 실행하고, command02부터는 실행하지 않을 생각이었다면 위와 같은 코드는 작성해서는 안됩니다. 위의 코드는 ERRORLEVEL이 1일 때만 정상 작동하고, 나머지 경우는 항상 사용자가 원하지 않는 작동을 하게 됩니다.
반드시 command01 명령만 실행하겠다면 다음과 같은 두 가지 방법이 있습니다.
- rem 방법1
- IF ERRORLEVEL 15 command15
- IF ERRORLEVEL 4 command04
- IF ERRORLEVEL 3 command03
- IF ERRORLEVEL 2 command02
- IF ERRORLEVEL 1 command05
우선 첫 방법으로는 위와 같이 큰 수부터 비교합니다. 2행에서는 종료코드가 15보다 크거나 같으면 command15 명령을 실행하게 되지요. 그러나 다음 행에 나오는 구문이 실행될 여지는 여전히 남습니다.
그럴 경우 다른 방법으로는 아래와 같이 정확한 수를 비교하게 만듭니다. 2행에서는 종료코드가 15보다 크거나 같고, 16보다 크거나 같지 않으면(작으면), 실행한다는 뜻입니다. 이러한 경우는 종료코드가 정확히 15인 경우뿐입니다.
- rem 방법2
- IF ERRORLEVEL 15 IF NOT ERRORLEVEL 16 command15
- IF ERRORLEVEL 4 IF NOT ERRORLEVEL 5 command04
- IF ERRORLEVEL 3 IF NOT ERRORLEVEL 4 command03
- IF ERRORLEVEL 2 IF NOT ERRORLEVEL 3 command02
- IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 command05
방법1에서는 goto 명령을 사용할 경우 오류가 생기지 않지만, 일반 명령을 사용할 경우에는 오류가 생길 수 있습니다.
방법2에서는 애초에 정확한 값을 비교하게 되므로 오류가 상당히 줄어들게 됩니다.
이와 비슷한 방법으로는 아래처럼 %ERRORLEVEL%을 쓰는 명령 확장이 있습니다.
- if /i %ERRORLEVEL% EQU 15 command15
위 문장은 문자열을 비교해 주는 if 구문입니다. 그런데 /i 선택사항이 들어감으로써 융통성을 지니게 되어 일반적인 비교를 하게 됩니다.
- IF ERRORLEVEL 4 (
- echo 파일을 백업하기에는 메모리가 부족하거나
- echo 드라이브가 잘못 지정되었거나 명령줄 구문이 틀립니다.
- ) ELSE IF ERRORLEVEL 2 (
- echo 사용자가 CTRL+C를 눌러 백업 작업을 강제 종료했습니다.
- )
위의 부분은 if 구문에 뒤따르는 명령이 하나가 아닐 때 쓰는 방법입니다. 명령이 하나가 아니라는 말은 같은 명령을 두 번 이상 쓸 경우에도 해당합니다. 위의 문장은 echo 명령을 두 번 썼기 때문에 ( ) (괄호)로 묶어야 합니다. 이러한 구문은 도스의 if와는 호환성이 없는 명령 확장 가운데 하나입니다.
또한 위에서 나타난 else 명령은 반드시 if 문의 끝에만 쓰일 수 있습니다. 또한 else 앞에는 반드시 ) (닫는 괄호)가 와야 합니다. 이때 else의 뜻은 "~이지 않고"라는 뜻이고, 위의 상황에서는 "종료코드가 4보다 크거나 같지 않고"라는 뜻이 됩니다. 뒤따르는 if 구문까지 합해서 해석하면 "종료코드가 4보다 작고, 2보다 크거나 같으면"이라는 뜻이 되지요. 종료코드가 3일 수도 있지만, XCOPY 명령은 종료코드 3을 가지지 않으므로 위의 구문은 정확히 실행됩니다.
또한 위의 방식은 구조적 프로그래밍 또는 절차적 프로그래밍에 근접한 방식입니다. GOTO 명령은 최대한 억제하여 꼭 필요한 경우에만 써야 읽기 좋고, 알아보기 좋고, 고치기 쉬운 코드가 됩니다.
관련 문서
다음 예고
이 글은 스프링노트에서 작성되었습니다.
GHOST.exe -CLONE,MODE=PDUMP,SRC=1:1,DST=1:2\GHOST.GHO-CLONE,MODE=PDUMP,SRC=1:1,DST=1:2\GHOST.GHO -Z9 -AUTO -SURE -RB
답글삭제IF ERRORLEVEL 1 (
ECHO FAULT
) ELSE (
ECHO EXEUTE
)
라고 보면..
저같은 경우 고스트 프로그램이 없으므로
0이아닌 에러 레벨이나와서(1,2,3,등)
if ERRORLEVEL 1 ->>> 이부분에서 참이 되는거 맞나요??? 에러레벨이 1이상이면 전부 1로 봐야되나요?
@진만고양이 - 2010/04/06 11:48
답글삭제IF ERRORLEVEL 정수
위 구문의 뜻은 "종료코드가 정수와 같거나 크면"이라는 뜻입니다. 다시 말해 정확하게 그 정수를 뜻하지는 않습니다.
정확하게 종료코드 1을 알아내는 구문은 다음과 같습니다.
if ERRORLEVEL 1 if not ERRORLEVEL 2
위 구문을 해석하면 " 종료 코드가 1보다 크거나 같으면, (그리고) 종료 코드가 2와 같지 않고 크지도 않으면" 이라는 뜻입니다.
다른 방법으로 if 문이 여럿 있을 때...
if ERRORLEVEL 9 명령1
if ERRORLEVEL 8 명령2
if ERRORLEVEL 7 명령3
...
if ERRORLEVEL 2 명령8
if ERRORLEVEL 1 명령9
이런 식으로 종료코드가 큰 값부터 차례대로 작게 작성하면 됩니다.
또한 ghost.exe 파일이 있는지를 먼저 검사하여 오류를 줄이면 됩니다. if exist 구문 참조
답변 감사합니다.. 주인장님 (^^)(__)
답글삭제ghost.exe 파일이 없으면 어떤값을 리턴을 해주는건가요??
0보다 큰 값을 리턴해주어서
위에서
IF ERRORLEVEL 1 부분이 참이되어 폴트가 출력되는게 맞는지요?
테스트해봤는데.. ghost.exe 파일이 없을때
C:\shell-test>iftest01.bat
'GHOST.exe'은(는) 내부 또는 외부 명령, 실행할 수 있는 프로그램, 또는
배치 파일이 아닙니다.
##########################################
## 백업 도중 오류가 발생했습니다. ##
##########################################
C:\shell-test>
라고 뜹니다. 제가 이해한게 맞죠? ''?
@진만고양이 - 2010/04/06 13:45
답글삭제파일이 없으면 ghost.exe에서 오류코드를 넘겨주지는 않습니다.
다만 도스의 command.com 파일이 오류코드를 넘겨줍니다. 이때도 1 또는 그보다 큰 값이 넘어옵니다.
앞의 오류 메시지를 보이지 않게 하려면 if exist 구문을 써서 파일이 있는지를 먼저 검사하면 됩니다.
@REM iftest03.bat 파일임
답글삭제@echo off
IF EXIST GHOST.exe (
ECHO 파일있음
GHOST.exe -CLONE,MODE=PDUMP,SRC=1:1,DST=1:2\GHOST.GHO -Z9 -AUTO -SURE-SURE -RB
IF NOT ERRORLEVEL 1 GOTO NOERROR
ECHO ##############################################
ECHO ## 백업 도중 오류가 발생했습니다. ##
ECHO ##############################################
GOTO END
:NOERROR
ECHO ##############################################
ECHO ## 백업 작업을 정상적으로 마쳤습니다. ##
ECHO ##############################################
GOTO END
) ELSE (
ECHO 파일 없어용
)
:END
ECHO ......
REM 이때 %ERRORLEVEL% 환경변수는 일종의 SET 명령명령 확장에 해당한다.
EXIT /B %ERRORLEVEL%
=====
위처럼 바꿧는데 돌아갑니다.
결과값이
파일없음
..........
이렇게나오는데 궁금한것은 ghost.exe 가돌아갈때
if문 에서 errorlevel 체크부분이 제대로 돌아가는지 궁금하네요
궁금 2)
답글삭제EXIT /B %ERRORLEVEL%
이것이 이해가 안되네요.
위에서 이것을 넣고 안넣고 하면
출력할때 빈줄이 하나더 나오나 안나오냐이던데
exit /h 하면
번호를 지정합니다. /B가 지정되면 ERRORLEVEL을
지정한 번호로 설정합니다. CMD.EXE를 끝내면,
프로세스 종료 코드를 지정한 번호로 설정합니다.
라고 설명되어잇는데 말이 무슨말인지 햇갈려용 쉽게 설명 좀 ^^;; 부탁드립니다.
@진만고양이 - 2010/04/07 13:58
답글삭제ghost.exe 파일은 도스용입니다. 윈도의 명령 프롬프트(흔히 '도스창')에서는 항상 오류가 납니다.
반면에 도스 상태에서는
IF EXIST GHOST.exe (
구문에서 오류가 납니다.
도스용 if 구문에서는 괄호( ( )를 지원하지 않습니다. 다시 말해 여는 괄호를 명령어로 인식하기 때문에 오류가 나고 맙니다.
@진만고양이 - 2010/04/07 14:01
답글삭제if errorlevel 구문에서 쓰는 오류코드(종료코드)의 값을 사용자가 직접 지정할 수 있다는 뜻입니다.
윈도용에서만 지원하고, 도스용에서는 지원하지 않는 기능입니다.
안녕하세요~!
답글삭제제가 질문을 많이하죠? ^^ㅋ
궁금한것이 있으면 풀어야 직성이 풀려서요
에러레벨 코드 관련 질문인데요
(..)아래처럼 코드 작성해서 결과값 얻는건데
제대로 된 결과가 나오면 0을
제대로 된 결과가 아닐경우 1인듯 한데
('')/ 위에 집필하신거 보면.. 0,1,2,3, 등 다양한데
저처럼 그냥 윈도우에서 도스창에서는 0,1 두가지만 나오도록
정해진건가요?
참고예제>
Terminal Service 입력시 에러코드 0
Terminal Service1 입력시 에러코드 1
Terminal Service23232 입력시 에러코드 1
===============================================
@echo off
echo. 터미널서비스 사용 여부 확인 >> %COMPUTERNAME%-1.txt
echo. >> %COMPUTERNAME%-1.txt
net START | find "Terminal Service1" > NUL
IF NOT ERRORLEVEL 1 GOTO TERMINAL-ACTIV >> %COMPUTERNAME%-1.txt
IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 ECHO ☞ 터미날서비스를 사용하지않음 ---ERRORLEVEL 1 >> %COMPUTERNAME%-1.txt
IF ERRORLEVEL 2 IF NOT ERRORLEVEL 3 ECHO ☞ 터미날서비스를 사용중이않음 ---ERRORLEVLE 2 >> %COMPUTERNAME%-1.txt
IF ERRORLEVEL 2 IF NOT ERRORLEVEL 3 ECHO ☞ 터미날서비스를 사용중이않음 ---ERRORLEVLE 2 >> %COMPUTERNAME%-1.txt
:EXIT
echo EXIT 터미널 서비스 비사용~~~!!!
PAUSE
EXIT
:TERMINAL-ACTIV
echo.
echo 터미널 서비스 사용~~~!!!
@진만고양이 - 2010/04/08 13:59
답글삭제2행... echo. 터미널서비스 사용 여부 확인 >> %COMPUTERNAME%-1.txt
화면에 나타나지 않음. 항상 %COMPUTERNAME%-1.txt 파일에 저장됨.
3행도 마찬가지.
4행에서... net START | find "Terminal Service1" > NUL
왜 찾는 메시지가 "Terminal Service1"인지요? "Terminal Service"가 옳습니다.
:EXIT
echo EXIT 터미널 서비스 비사용~~~!!!
PAUSE
EXIT
위에서 마지막에 붙은 exit 보다는
goto :eof
라고 하는 쪽이 더 낫습니다.
exit의 경우 명령 프롬프트를 닫아 버립니다. 물론 그 배치파일 하나만 쓴다면 별 상관 없습니다만, 그다지 조흔 코드는 아닙니다.
또한 종료코드에 관한 문제는 find 명령을 살펴보시기 바랍니다.
네 일부러 COMPUTERNAME-1.TXT 에 저장하게 했습니다.
답글삭제4행은 일부러 Terminal Service1 1을 붙여봐서 에러코드가 뭐가 나오나 했더니 1이 나오더라고요 (에러코드가 뭐가나오나 궁금해서 실험해봄)
아
여기서도 eof 를 쓰는군요
프로그래밍 할때 end of file 해서 eof 쓰는데
도스에서도 있는줄 몰랐습니다.
댓글 이렇게 잘 달아주시니 정말 감사합니다 (^^)(__)
@진만고양이 - 2010/04/08 16:22
답글삭제도스용 배치파일에서는 없습니다. 이 :eof 레이블은 윈도용에만 있는 가상의 레이블입니다.