MenuIcon

Owl-Networks Archive

LoginIcon

Win32 / Perl 스크립트 내에서 다른 Perl 스크립트 또는 프로그램을 실행하기

| 분류: Perl | 최초 작성: 2012-04-04 17:45:39 |

이 문서는 네이버 카페 Perl Community & Study 에 간략하게 작성했던 것을 일반 목적으로 풀어 쓴 글입니다.

1. Perl 스크립트 내에서 외부 프로그램 실행하기 - system(), exec()

코드를 작성하다 보면 하나의 스크립트 내에서 다른 스크립트나 프로그램을 실행해야 할 경우가 종종 있습니다. 물론, 실행해야 할 내용이 Perl 스크립트라면, 그것을 모듈의 형태로 만들어서 use 또는 require 를 이용하여 주 코드 내에 include 한 후에 데이터를 처리할 수 있을 것입니다. 그러나 그것이 불가능한 경우나, 아니면 실행할 대상이 Perl 스크립트가 아닌 어플리케이션 바이너리인 경우에는 이렇게 할 수가 없죠. 이럴 때는, 실행할 대상인 외부 프로그램을 실행하고, 그 결과값을 Perl 스크립트가 다시 받아오는 방법이 필요해집니다. 이럴 때에 사용할 수 있는 Perl 내부 함수가 있으니, 바로 exec() 나 system() 명령입니다.

이들 두 함수의 역할은 똑같습니다. 외부 명령이나 프로그램을 실행해 주죠. 그러나 그 이후의 처리가 서로 다릅니다. exec() 의 경우에는 지정한 임의의 명령을 실행한 후 그 실행이 종료되어도 영영 원래의 프로그램으로 안 돌아옵니다. 안 돌아오는 정도가 아니라 아예 exec() 를 실행한 스크립트 자체가 종료되어 버립니다. 대개의 경우에는 이런 상황을 바라면서 코딩을 하지는 않겠지요. (특히 윈도우에서는요.) 그래서, 보통 외부의 프로그램을 실행해야 할 필요성이 있는 경우 그 선택은 system() 이 되곤 합니다.

2. system() 함수

보통의 system() 함수의 사용은 아래와 같은 형태가 됩니다. 예를 들면 apprun.exe 가 무언가를 처리해서 그 결과가 성공이면 1을, 실패하면 0을 돌려준다고 할 때, 이런 형태로 코드를 작성할 수 있겠죠.

my $retValue = system( "apprun.exe" );

if ( $retValue == 1 ) {
    print "Process OK!
";
}
else {
    print "Process Error!
";
}

undef $retValue;

위와 같은 코드가 실행 되면, Perl 은 일단 apprun.exe 를 실행하고, 그 실행이 끝날 때까지 기다립니다. 그리고, apprun.exe 가 종료되면서 어떤 반환값을 남긴다면, 그 반환값은 $retValue 스칼라 변수 내에 저장됩니다. 위와 같은 예시에서라면 $retValue 의 값은 0 아니면 1이 되겠죠. 이제 그 값을 확인하여 적절한 처리 - 성공인지 실패인지 알리기 - 를 해 주면 되겠습니다. 간단하죠?

그러나, system() 함수는 그 실행 형태로 인하여 한 가지 문제점을 갖습니다. 바로 그 실행 대상이 종료될 때까지 계속 대기를 한다는 것이죠. 아니, 보통은 그래야 정상이고, 또 그래야 할텐데요? 네. 그런데 만약 apprun.exe 의 처리 시간이 한 몇 시간쯤 걸린다면 어떨까요? 그 몇 시간 동안 메인 스크립트는 아무 것도 못 하고 놀아야 됩니다. 만약 apprun.exe 가 실행 도중 다운이라도 되면, 메인 스크립트는 오지 않을 반환값을 기다리며 무한정 놀게 될 겁니다. 굳이 처리를 기다리지 않아도 되는 다른 작업 목록이 있다면, apprun.exe 가 자신의 작업을 처리하는 동안 미리 처리를 진행하는 것이 효율적입니다. (이런 형태의 처리를 "병렬처리"라고 한답니다만, 이 부분은 저에게 눈꼽만큼의 지식도 없으므로 넘어가겠습니다. 이런 건 전공하신 분들께 물어보세요.)

더 문제는, 만약 실행하려는 대상 프로그램이 무언가를 처리한 후 값을 돌려주고 종료하는 형태의 프로그램이 아니라, 그 자신도 계속 돌아가면서 무언가를 처리하는, 이를테면 서버 데몬 같은 프로그램인 경우입니다. 메인 스크립트는 자신이 실행한 프로그램이 종료되고 무언가 반환값이 돌아오기를 눈이 빠지라 기다리고 있는데, 정작 그 프로그램은 계속 돌아가면서 자신의 일을 할 뿐 자신의 실행을 종료하거나 무언가 데이터를 넘겨줄 생각이 눈꼽만큼도 없습니다. 만약 이런 실행 형태를 보이는 외부 프로그램이라면, system() 함수로는 실행이 불가능합니다. 메인 스크립트가 사실상 다운된 것과 같은 상황에 빠질 테니까요.

3. 스크립트 내에서 무한 루프 형태인 외부 프로그램을 실행하기

일단 윈도우 환경에서, Perl 내부 함수만으로 이런 문제를 간단히 해결하기는 어려울 것 같다는 생각이 듭니다. 그러나, 만약 현재 윈도우용 Perl 스크립트의 GUI 구현 방법으로서 Win32::GUI 를 사용하고 있다면, 이러한 문제를 아주 간단하게 회피할 수 있습니다. 바로, Win32::GUI 에서 제공하는 ShellExecute 메서드를 사용하는 것입니다. 아래는 예제 스크립트입니다.

my $MAIN_WIN = Win32::GUI::Window->new(
   -name  => "MAIN_WIN",
   -title => "윈도우 테스트",
);

my $STATUS_BAR = $MAIN_WIN->AddStatusBar();

# (...중략...)

my $retValue = $MAIN_WIN->ShellExecute('open',"apprun.exe",'','',1);

if ( $retValue > 32 ) {
    $STATUS_BAR->SetText( 0," 프로그램이 시작되었습니다.");
}
else {
    $STATUS_BAR->SetText( 0," 프로그램을 시작하지 못했습니다($retValue).");
}

undef $retValue;

일단, $retValue 는 apprun.exe 가 돌려주는 모종의 처리 결과 반환값이 아닙니다. apprun.exe 가 제대로 실행 되었는지에 대한 결과값입니다. 이런 종류의 처리에서는 실행되는 외부 프로그램에서 처리 결과값을 넘겨받을 필요가 없기 때문에, 해당 프로그램이 제대로 실행되었는지에 대한 시스템 코드만을 받을 뿐입니다. ShellExecute 가 돌려주는 값($retValue에 저장되는)이 32보다 크다면 프로그램이 성공적으로 실행된 것이며, 32 또는 그 이하의 값이라면 무언가 문제가 생긴 것입니다. 예를 들어, ShellExecute 돌려준 값이 2라면, apprun.exe 파일이 존재하지 않아서 실행하지 못했다는 의미가 됩니다. (32 이하의 에러 코드에 대한 구체적인 내용은 이 문서의 ShellExecute 항목을 참조하십시오.)

아무튼, 이렇게 실행된 apprun.exe 는 원래의 메인 스크립트와 상호작용 없이 그냥 자기 일을 할 뿐입니다. 메인 스크립트 역시, ShellExecute 가 돌려주는 반환값이 32 이상이라면 "프로그램 제대로 실행 됐음! 관심 끝!" 을 외치고 더 이상 신경 쓰지 않게 됩니다. 의도대로 됐네요.

참고로, 이 ShellExecute 로 열 수 있는 것은 실행 파일만이 아닙니다. 윈도우 환경에서 바로 웹 페이지를 열 수도 있고(물론 인터넷 익스플로러가 실행됩니다), 다른 Perl 스크립트를 실행할 수도 있습니다. 흔히 윈도우 도움말 파일로 많이 사용된 CHM 파일을 열 수도 있고... 쓰기 나름입니다. 아래는 각종 사용례들입니다.

my $retValue = $MAIN_WIN->ShellExecute('open',"http://www.naver.com/",'','',1);
my $retValue = $MAIN_WIN->ShellExecute('open',"help.chm","",'',1);
my $retValue = $MAIN_WIN->ShellExecute('open',"perl.exe","script.pl",'',1);

먄약, 윈도우 환경에서 .pl 확장자를 perl.exe 와 연결해 놓았다면, 이렇게도 가능합니다.

my $retValue = $MAIN_WIN->ShellExecute('open',"script.pl",'','',1);

Win32::GUI 를 사용하지 않더라도, 윈도우 환경에서 Win32::API 를 이용하여 직접 shell32.dll 을 호출하여 ShellExecute 를 실행하는 방법으로 사용할 수도 있습니다. 이에 대한 자세한 설명은 생략합니다.

☞ 태그: system(), ShellExecute, Win32::GUI, exec(),

☞ 트랙백 접수 모듈이 설치되지 않았습니다.

☞ 덧글이 없고, 트랙백이 없습니다.

덧글을 남기시려면 여기를 클릭하십시오.
[483] < [435] [434] [432] [429] [426] ... [424] ... [423] [422] [421] [420] [419] > [19]

(C) 2000-2018, Owl-Networks. Powered by Perl. 이 페이지는 HTML 5 표준에 따라 작성되었습니다.