Useful Solutions2014. 9. 26. 09:39

오랫만에 구관이 명관 시리즈를 업데이트해봅니다. 이번 아티클은 작지만 확실히 유용한 팁 하나를 소개해볼까 합니다. 배치 파일을 작성하고 배포할 때 가장 큰 문제가 되는 것이, 배치 파일이 의도하지 않은 디렉터리 경로 상에서 실행된다는 점일 것입니다.

 

 

예를 들면 배치 파일을 명령어나 다른 프로그램을 이용하여 실행하면 배치 파일이 있는 경로가 아닌 호출한 프로그램의 현재 디렉터리 경로 위에서 실행되어서 문제가 될 때가 있습니다. 물론 배치 파일의 이런 특성을 활용해야 하는 경우도 있겠습니다만, 보통은 배치 파일을 실행할 때 정확히 해당 경로 상에서 어떤 작업을 하도록 의도한 것이 많으므로 이런 특성은 불편할 수 있습니다.

이 문제를 수정하려면 배치 파일의 경로를 항상 정확하게 알 수 있어야 하는데, 이럴 때 %~dp0 환경 변수를 사용하면 쉽게 문제를 해결할 수 있습니다. 하지만 무작정 cd 명령을 사용하면 배치파일이 끝나고 난 다음에 디렉터리 위치가 원래대로 돌아오지 않는 문제가 남습니다.

이런 문제를 해결하기 위하여, 새로 작성하는 배치 파일의 시작과 끝을 아래의 코드처럼 작성하도록 하면 편리할 것입니다.
@echo off
pushd "%~dp0"

rem 여기에 배치 파일 본문을 작성합니다.

:exit
popd
@echo on


 

내용은 단순합니다. 실행하는 명령줄이 보이지 않게 @echo off로 감추고, pushd 명령을 사용하여 스택에 현재 디렉터리 경로를 push하고 새 위치로 이동한 다음 원하는 일을 하는 것입니다. 그리고 나중에 종료할 때에는 popd 명령을 사용하여 직전에 저장한 디렉터리 경로를 꺼내와 그 위치로 다시 이동하고 @echo on으로 (심미성을 위하여 @echo on이라고 썼습니다.) echo 상태를 복원합니다. 여기서 :exit 라벨은 프로그램 내에서 탈출 조건을 만났을 때 편리하게 활용할 수 있도록 하기 위한 것입니다.

위의 예제를 활용하면 다음과 같이 응용할 수 있습니다.

@echo off
pushd "%~dp0"


if not exist %windir%\system32\runas.exe. (
    echo RUNAS.EXE 프로그램을 찾을 수 없습니다.
    pause
    goto exit
)

for /r "%~dp0" %%v in (test.cmd) do (
    if exist "%%v" (
        echo %%v 진행 중...
        call "%%v"
        rem 다른 배치 파일을 호출하고나면 echo on 상태가 되므로 다시 @echo off로 꺼줍니다.
        @echo off
    )
)

:exit
popd
@echo on


 

위와 같이 활용한다면 배치 파일을 어디서 실행하든 원하는 경로로 들어갔다가 다시 쉽게 원래 위치로 되돌아올 수 있으므로 일반 프로그램처럼 배치 파일을 작성하는 것이 좀 더 쉬워집니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요

Useful Solutions2010. 1. 15. 16:45

지난번 강좌에 이어서 오늘은 if 문을 사용하여 파일, 디렉터리, 프로그램의 실행 결과를 평가하는 방법, 파일 출력을 수행하는 방법, 그리고 명령줄 인수를 받아들이는 방법을 살펴보도록 하겠습니다. 앞서 살펴본 강좌의 비교 연산자 기능을 바탕으로, 실제 수행 결과를 평가할 수 있다면 배치 파일 구문을 스크립트 프로그래밍 언어처럼 활용할 수 있을 것입니다.

 

1. 파일 및 디렉터리의 존재 여부를 판정하기

 

파일 및 디렉터리의 존재 여부를 판정하기 위하여 exist 키워드를 사용할 수 있습니다. 다음은 if문와 exist 키워드를 조합한 예시입니다.

 

if exist "%windir%\fonts\consola.ttf" echo Your system has Consola font.

 

위의 구문에서 exist 키워드 다음에 오는 인자는 존재 여부를 검사하고자 하는 경로에 대한 것으로, 환경 변수를 사용하여 혼합할 수도 있습니다. 또한, exist 키워드 앞에 not 키워드를 붙여 부정의 의미로 명령을 실행하여 결과를 뒤집는 것도 가능합니다.

 

if not exist "%windir%\fonts\consola.ttf" echo Your system does not have Consola font.

 

만약 디렉터리의 존재 여부를 파악하고자 한다면 파일 경로 대신 디렉터리 경로 대입만 하면 됩니다.

 

if exist "%windir%" echo WINDIR environment variable contains valid path.

 

여기서 한 가지 생각해봐야 할 문제점이 있는데, Windows의 경우 기본 배치 파일 명령만으로는 존재한다고 인지된 대상이 실제로 파일인지 디렉터리인지 파악할 방법이 명확하지 않다는 문제점이 있습니다.

 

파일 및 디렉터리 관련 API를 호출하면서 파일이나 디렉터리를 생성할 수 없다는 오류를 만나는 경우가 종종 있는데, 대개의 경우 권한 문제로 볼 수 있지만, 아주 드물게 디렉터리가 생성되기를 기대한 위치에서 같은 이름의 확장자가 없는 파일이 존재하여 이름이 겹치게 되어 동작이 실패할 수 있고, 반대의 경우도 있을 수 있습니다.

 

이 문제는 배치 파일에 대한 문제 뿐만이 아니라, Win32 프로그래밍을 하면서도 한번쯤 고려해볼 필요가 있는 주제일 것입니다.

 

2. 프로그램의 실행 결과를 판정하기

 

표준 Windows 배치 명령어를 통하여 프로그램의 실행 결과를 판정하는 방법은, 유닉스 기반 시스템의 경우처럼 프로그램이 반환하는 종료 코드를 기준으로 하는 것이 보편적입니다. 명령줄 해석기의 경우, 이를 %ERRORLEVEL% 변수에 보관하며, 우리가 앞서 살펴본 강좌에서처럼 %ERRORLEVEL% 변수에 대해 연산자를 사용하여 코드를 분석할 수 있습니다. 그리고 지금 소개하는 errorlevel 키워드를 if 문과 조합하여 사용하는 방법도 있습니다.

 

if errorlevel 0 echo Program is succeeded.

 

위와 같이 작성하면, 실제로는 %errorlevel% geq 0 로 해석되는 것입니다. 그리고 errorlevel 키워드 앞에 not이 붙으면 geq에 대한 대우 연산자 lss로 의미가 바뀌어 실제로는 %errorlevel% lss 0로 해석될 것입니다.

 

3. 간단한 파일 출력

 

보통의 경우, 리디렉션을 이용하여 프로그램이 표준 출력 스트림에 송신하는 컨텐츠를 하드디스크에 파일로 저장하는 기법을 많이 이용합니다. 이를 좀 더 응용하면, 연속되는 내용을 쌓아서 보관할 수도 있으므로, 이제까지 설명한 기법들을 이용하여 프로그램의 실행 결과나 변수의 내용을 분석하여 출력 파일을 작성하는 똑똑한 배치 파일도 작성할 수 있습니다.

 

echo "Hello World!" > test.txt

echo "Overwrited?" > test.txt

 

위와 같이 작성할 경우, > 연산자는 파일 연산에서 매번 새로운 파일을 만들고 덮어쓰는 의미로 해석되므로 먼저 실행한 명령어에 의하여 저장된 문자열이 담긴 파일은 사라지고, "Overwrited?" 문자열만을 보관하는 파일만 남게 됩니다. 그렇다면, 두 줄을 이어서 저장하려면 어떻게 바꾸어야 할까요? ">" 대신 ">>" 연산자로 바꾸면 답이 됩니다.

 

echo "Hello World!" >> test.txt

echo "Overwrited?" >> test.txt

 

이와 같이 작성한 파일을 화면에 출력하고 싶다면 con 이라는 예약 장치명을 지정하면 됩니다.

 

copy test.txt con

 

PRN이나 LPT1과 같은 예약 장치명이 동작한다면, 사실 더 좋을 수 있겠지만, 아쉽게도 이러한 예약 장치명을 사용하면 경우에 따라서는 인쇄 기능이 실행되지 않는 대신 명령줄 인터프리터의 실행이 중단되고 맙니다. 인쇄 기능을 사용하고자 한다면, 해당 파일에 관련이 있는 소프트웨어의 인쇄 기능을 대신 사용하는 것이 좋습니다. 메모장이나 워드패드의 경우, /p 스위치 다음에 파일 이름을 지정하여 파일을 인쇄하도록 지시할 수 있습니다.

 

notepad /p test.txt

wordpad /p test.txt

 

4. 명령줄 매개 변수 받아들이기

 

명령줄 매개 변수를 받아들이도록 배치 파일을 구성하면, 배치 파일의 활용 용도가 한층 더 깊어질 수 있습니다. 이 기능은 기본으로 제공되는 기능으로 %0 부터 %9까지의 예약 변수를 활용하면 쉽습니다. 이들 예약 변수는 C 언어를 사용하여 작성하는 main() 메서드의 char **argv 변수에서처럼 0번째 인덱스는 실행하는 배치 파일 그 자체의 Full Path를 포함하고, 1부터 실제 명령줄 인자가 포함됩니다.

 

@echo off

echo %0

if %1 equ Test echo Hello World

echo on

 

위와 같이 프로그래밍한 배치 파일을 Hi.bat 으로 저장하였을 때, 명령줄에서 아래와 같이 명령을 입력하면 Hello World라는 문구가 나타나는 것을 볼 수 있습니다.

 

Hi.bat Test

 

배치 파일 명령줄을 위한 인수로 공백을 포함한 문자열을 넘길 필요가 있을 때는, 기존과 마찬가지로 따옴표로 감싸어 넘기면 동일하게 동작합니다.

Posted by Cloud Developer 남정현 (rkttu.com)

댓글을 달아 주세요