시작하기
우선 간단한 명령줄 배치 파일을 살펴보자.
@echo off rem This is a comment! echo Hi
@echo off는 거의 모든 명령줄 스크립트에 쓰며 보통 첫번째 줄에 놓는다. @echo off 가 없다면 아래와 같이 명령어 실행 과정을 일일이 보여준다. 보통은 사용자가 원치 않는 행동이다.
c:>a.bat c:>rem This is a comment! c:>echo Hi Hi
rem은 주석 지시자로 생각하면 된다. C++의 // 와 동일한 역할을 한다.
ERRORLEVEL
윈도우 응용프로그램처럼 명령줄 배치 파일에도 종료 코드(exit code)가 있다. C++ 프로그램에선 main 함수의 반환값인 종료 코드를 명령줄 배치에선 오류 수준(ERRORLEVEL)이라 부른다. 일반적인 관례에 따르면 종료 코드 0은 성공을 의미하고 나머지 값은 실패를 뜻한다.
ERRORLEVEL 설정하기
명령줄 배치 스크립트에서 종료 코드를 명시적으로 반환할 땐 exit 명령어를 쓴다.
@echo off rem This is a comment! echo Hi exit /b 0
/b
옵션이 있으면 배치 스크립트를 종료한다. 그렇지 않으면 아예 CMD.exe
프로세스를 종료시키므로 주의한다.
주의! 윈도우 버전에 따라 종료 코드를 반환하는 방식이 다른데 exit /b
는 윈도우 2000 부터 도입됐다. 그 이전 버전에 대해 알고 싶다면 Errorlevels를 참고하자.
ERRORLEVEL 확인하기
배치 파일의 성공 여부를 알고자 한다면 명령줄에 다음과 같이 입력한다.
c:>a.bat Hi! c:>echo %errorlevel% 0
인자 넘겨받기
인자는 그 순서대로 %0, %1, %2 식으로 지칭하면 된다. 단 %0은 배치 파일의 이름을 나타내는 특수 인자임을 주의한다.
@echo off echo filename = %0 xcopy /E %1 %2 exit /b 0
이 스크립트는 자신의 이름을 메시지로 내보낸 후 첫 번째 인자로 받은 디렉터리 트리를 두 번째 인자로 받은 경로에 복사한다.
c:>a.bat a a1 filename = a.bat 0 File(s) copied
마지막으로 특별한 인자 지시자 "%"를 소개한다. "%"는 모든 인자를 묶은 문자열을 나타낸다. 위의 코드에선 "a a1"이 된다.
사용자 입력 받기
표준입력장치에서 사용자의 입력을 받아 출력하는 예제를 보면 이해하기 쉽다.
@echo off rem This is a comment! set /p name=What is your name? echo Your name is %name%. exit /b 0
이 배치 스크립트를 실행하면 다음과 같은 결과를 얻는다.
c:>a.bat What is your name? Jay Your name is Jay.
첫 번째 Jay는 사용자가 키보드로 입력한 값이다.
변수
SET
SET 명령을 사용하면 변수 선언이 가능하다.
@echo off rem this is "conditional.bat". set var1=first variable echo %var1% exit /b 0
이 방법의 특징은 스크립트가 종료된 후에도 선언한 변수는 유효하다는 것이다. CMD.exe가 종료되기 전까진 유효하다.
F:WorkspaceWinBatch>conditional.bat first variable F:WorkspaceWinBatch>set var1 var1=first variable
스크립트 내에서만 유효한 변수
위의 방법과 달리 스크립트 종료 후에 변수 선언을 무효로 만들려면 setlocal을 이용한다.
@echo off rem this is "conditional.bat". setlocal set var1=first variable echo in the local: %var1% endlocal echo out of the local: %var1% exit /b 0
F:WorkspaceWinBatch>conditional.bat in the local: first variable out of the local:
SETX
SET 로 만들거나 값을 변경한 변수는 명령 줄 프로세스(CMD.exe)가 살아있는 동안만 유효하다. 이러한 제한을 벗어나려면 사용자/시스템 환경 변수를 직접 조작하는 수밖에 없다. SETX 는 이런 기능을 제공한다.
시스템 PATH 값을 조작하기
/M
스위치가 있으면 시스템 환경 변수를 바꾸고, 그렇지 않으면 사용자 환경 변수를 변경한다.
SETX PATH "%PATH%;C:Temp" /M PATH 값을 조작할 때는 경로 끝에 이 붙지 않게 한다. 그래야 오류가 나지 않는다. 다음과 같은 명령은 재앙을 일으킬 수도 있다.
SETX PATH "%PATH%;C:Temp" /M #### 특수 변수 ##### %RANDOM% 0 ~ 32767 사이의 값을 무작위로 뽑아 반환한다.
c:>echo %RANDOM% 30401
%CD%
현재 작업 디렉터리를 나타낸다.
@echo off rem D:test.bat echo %CD%
C:에서 D:에 있는 test.bat 파일을 실행하면 다음과 같은 결과가 나온다.
C:>D:test.bat C:
%0 외
%0 계열의 변수는 작업 디렉터리가 하닌 배치 스크립트의 경로를 기준으로 값을 정한다.
UNC 경로일 때
%0 = "\\serverusersmystuffTempMy TestMy Batch File.cmd" %~0 = \\serverusersmystuffTempMy TestMy Batch File.cmd %~d0 = \\ %~p0 = serverusersmystuffTempMy Test %~dp0 = \\serverusersmystuffTempMy Test
드라이브 경로일 때
%0 = "H:TempMy TestMy Batch File.cmd" %~0 = H:TempMy TestMy Batch File.cmd %~d0 = H: %~p0 = TempMy Test %~dp0 = H:TempMy Test
%DATE% 과 %TIME%
각각 오늘 날짜와 현재 시간을 반환한다.
c:>echo %DATE% %TIME% 2009-10-06 17:56:50.53
서버의 언어 설정에 따라선 포맷이 다르기도 하다.
c:>echo %DATE% %TIME% Tue 10/06/2009 17:56:50.53
그러므로 %DATE%를 파싱할 땐 특히 주의해야 한다. 아래 코드는 후자(지역 언어: 영어)에서만 제대로 작동한다.
@echo off echo %DATE% %TIME% set MTH=%DATE:~4,2% set DAY=%DATE:~7,2% set YR=%DATE:~10,4% set HR=%TIME:~0,2% set HR0=%TIME:~0,1% if "%HR0%"==" " set HR=0%TIME:~1,1% set MIN=%TIME:~3,2% set SEC=%TIME:~6,2% set MYDATE=%YR%%MTH%%DAY%-%HR%%MIN%%SEC% echo %MYDATE%
그밖의
마이크로소프트 사가 제공하는 Command shell overview 문서를 참고한다.
조건문
if exist
파일이름
파일의 존재 여부를 확인할 때 사용한다.
@echo off rem this is "conditional.bat". if exist conditional.bat echo there it is! if not exist no.bat echo it doesn't exist! exit /b 0
이 배치 스크립트의 결과는 다음과 같다.
F:WorkspaceWinBatch>conditional.bat there it is! it doesn\'t exist!
if defined
변수의 존재 여부를 확인할 때 사용한다.
@echo off rem this is "conditional.bat". setlocal set var1=first variable if defined var1 echo val1 is there! if not defined var2 echo val2 is not there! endlocal exit /b 0
이 배치 스크립트의 결과는 다음과 같다.
F:WorkspaceWinBatch>conditional.bat val1 is there! val2 is not there!
if 문자열1==문자열2
@echo off setlocal set var1=variable set var2=variable set var3=some-variable if %var1% == %var2% (echo var1 equals to var2) else (echo var1 not equals to var2) if %var1% == %var3% (echo var1 equals to var3) else (echo var1 not equals to var3) endlocal exit /b 0
이 배치 스크립트의 결과는 다음과 같다.
F:WorkspaceWinBatch>test.bat var1 equals to var2 echo var1 not equals to var3
비교 연산자
- EQU – equal
- NEQ – not equal
- LSS – less than
- LEQ – less than or equal
- GTR – greater than
- GEQ – greater than or equal
대소문자 구분
기본적으로 문자열 비교시 대소문자 구분 을 한다. 만약 대소문자의 구분 없이 비교하고 싶다면 /I 옵션을 주면 된다.
@echo off setlocal set var1=variable set var2=variable set var3=VARIABLE if %var1% EQU %var2% (echo var1 equals to var2) else (echo var1 not equals to var2) if %var1% EQU %var3% (echo var1 equals to var3) else (echo var1 not equals to var3) if /I %var1% EQU %var3% (echo var1 equals to var3) else (echo var1 not equals to var3) endlocal exit /b 0
이 배치 스크립트의 결과는 다음과 같다.
F:WorkspaceWinBatch>test.bat var1 equals to var2 echo var1 not equals to var3 var1 equals to var3
if errorlevel
{{미완성}}
for 를 이용한 순회
주의! 변수 이름은 대소문자를 구분한다!
문자열, 명령 출력값 파싱하기
/f 옵션을 쓰면 파일, 문자열, 명령 출력값에서 필요한 텍스트를 검사하고 찾아낼 수 있다. 이를테면,
for /f %%a in ('cd') do set MYROOT=%%a
이 배치 파일은 명령줄에서 cd를 실행시키고 그 결과(현재 디렉터리의 경로) %%a 변수에 저장한다. 그런 후 MYROOT라는 환경변수에 현재 디렉터리의 경로를 입력한다.
참고 문헌
문자열 다루기
문자열 추출
문자열의 인덱스 값을 지정해 부분 문자열을 뽑아낼 수 있다. 대부분의 부분 문자열 메서드와 마찬가지로 첫 매개변수는 시작 지점이고 두 번째 매개변수는 문자열의 길이이다.
예제 1
@echo off set str=politic echo.%str% set str=%str:~0,4% echo.%str%
politic poli
예제 2
@echo off echo.Date : %date% echo.Weekday: %date:~0,3% echo.Month : %date:~4,2% echo.Day : %date:~7,2% echo.Year : %date:~10,4%
Date : Sat 03/11/2006 Weekday: Sat Month : 03 Day : 11 Year : 2006
예제 3
@echo off set str=politic echo.%str% set str=%str:~1,-1% echo.%str%
politic oliti
예제 4
set str=politic echo.%str% set str=%str:~-4% echo.%str%
politic itic
참고 문헌
고급 기법
래퍼 파일
만약 msbuild.exe를 쓸 생각이라면 어떨까? 닷넷 프레임워크의 버전마다 msbuild.exe 바이너리가 따로 있으며 그 경로는 매우 복잡하다. 이런 경우엔 다음과 같이 배치 파일을 만들면 된다.
@echo off "C:WINDOWSMicrosoft.NETFramework64v3.5msbuild.exe" %*
이게 끝은 아니다. msbuild.exe의 종료 코드를 받아 전달해야 완전한 래퍼 파일이 된다.
rem NewMSBuild.bat @echo off C:WINDOWSMicrosoft.NETFramework64v3.5msbuild.exe %* exit /b %errorlevel%
이보다 복잡한 스크립트라면 고려할 점이 또 있다. 배치 스크립트에선 환경변수를 조작하는 일이 흔하다. 그러나 스크립트 종료 후에 환경 설정을 원래대로 돌리고 싶은 게 보통이다. 여러 방법이 있지만 가장 간단한 방법만 보자.
rem MyMSBuild.bat @echo off CMD.exe /K NewMSBuild.bat %* SET ERR_LEVEL=%errorlevel% exit /b %ERR_LEVEL%
이 예제는 환경 변수를 조작하는 코드는 모두 NewMSBuild.bat에 있다고 가정한다. 새 인터프리터를 띄우고 그 안에서 환경 변수를 조작한다. 스크립트를 다 실행한 후 인터프리터가 종료되고 그와 동시에 스크립트 안에서 조작한 환경 변수는 모두 날아간다.
현재 디렉터리 #1
현재 디렉터리를 구하는 방법은 다음과 같다.
@echo off rem little complicated SETLOCAL for /f %%a in (\'cd\') do set MYROOT=%%a echo %MYROOT% ENDLOCAL rem more easiler way echo %CD%
두 번째는 시스템이 제공하는 의사 변수인 %CD%를 사용한다. %CD%가 없는 시스템에선 첫 번째 방법처럼 CD 명령을 실행시켜 그 출력값을 가져오면 된다.
현재 디렉터리 #2
CD 명령이나 %CD% 의사 변수를 사용하는 방법엔 문제가 있다.
@echo off rem F:WorkspaceWinBatchdirshow.bat echo this is %%cd%% %cd% echo this is %%~dp0 %~dp0
F:WorkspaceWinBatch 폴더에 dirshow.bat 란 배치 파일이 있다고 하자. dirshow.bat를 F:WorkspaceWinBatch에서 실행하면 예상했던 출력값이 나온다.
F:WorkspaceWinBatch>dirshow.bat F:WorkspaceWinBatch> this is %cd% F:WorkspaceWinBatch this is %~dp0 F:WorkspaceWinBatch
그러나 C:에서 dirshow.bat를 실행시키면 다른 결과가 나온다.
c:>F:WorkspaceWinBatchdirshow.bat this is %cd% c: this is %~dp0 F:WorkspaceWinBatch
CD는 명령을 실행한 경로를 반환한다. 그에 반해 %~dp0%은 배치 스크립트 파일의 경로를 반환한다. 상황에 맞는 방법을 선택하면 된다.
부모 디렉터리
제일 쉬운 방법은 %~dp0% 를 이용하는 것이다.
@echo off rem D:WorkspaceWinBatchdirshow.bat echo this is %%~dp0 %~dp0..
이 방법의 단점은 경로가 지저분하다는 점이다.
D:WorkspaceWinBatch..
조금 더 깔끔한 경로를 원한다면 이렇게 한다.
@echo off rem F:WorkspaceWinBatchdirshow.bat for %%? in ("%~dp0..") do echo %%~f?
D:Workspace
잘 정리된 문서네요. 감사합니다.~
도움이 되었다니 기분 좋네요