my %ENV ? local %ENV ?

전종필

local이냐 ? my냐?
대개의 경우 우리는 my를 사용합니다.
이유가 어찌 되는지는 잘 모르겠지만, my가 빠르다니까... (이유를 알고 싶으시면 Advanced Perl Programming를 한 번 읽어 보실 것을 권합니다.)

그런데, 모든 Perl 프로그램에는 프로세스 자신의 환경변수를 갖는 %ENV라는 해쉬가 있습니다.
%ENV 해쉬는 부모 프로세스의 내용을 그대로 계승받습니다. 대개의 경우 부모 프로세스는 셸입니다. 그래서 셸의 환경변수를 그대로 받아오게 되어 있습니다.
하지만, 부모 프로세스가 다른 프로그램이라면, 그 프로그램의 환경변수를 받아오는데, 그 부모 프로세스가 Perl 프로그램인 경우에도 마찬가지 입니다. 따라서 어떤 Perl 프로그램 top에서 다른 프로그램 exe를 system함수를 통하여 다음과 같이 실행하면


# top
$ENV{PARENT} = $0;
system('./exe');
자식 프로세스인 exe의 프로세스는 $ENV{PARENT}를 접근할 수 있게 됩니다.

# exe
$father = $ENV{PARENT};
그런데, 만일 부모프로세스에서 자식 프로세스의 환경변수에는 자신의 것과 다른 내용을 넣어 주고 싶지만 자신의 환경변수에는 변화를 주고 싶지 않을 수 있습니다. (특히 프로그램이 오랫동안 실행되는 서버들이 그렇습니다.) 이럴 때는 어떻게 해야 할까요?
my 를 이용하여 자식 프로세스를 위한 %ENV를 준비하고 싶을 수도 있습니다. 다음의 간단한 예를 봅시다.

#!/usr/bin/perl
# top
print '-' x 80, "\n$0\n";
print join ' ', keys %ENV;
print "\n";

######

if( -x './exe' ) {
        my %ENV;
        %ENV = qw( aa 1 bb 2 cc 3 dd 4 );
        system('./exe');
}

print '-' x 80, "\n$0\n";
print join ' ', keys %ENV;
print "\n";
그리고,

#!/usr/bin/perl
# exe
print '-' x 80, "\n$0\n";
print join ' ', keys %ENV;
print "\n";
위의 프로그램은 얼핏 성공적일 것 같지만, 사실은 그렇지 않습니다. 다음은 출력내용입니다. (여러분의 시스템은 내용이 다를 수 있습니다.)

--------------------------------------------------------------------------------
./top
_ QTDIR LS_COLORS SHLVL KDEDIR HISTSIZE OSTYPE PWD SSH_TTY INPUTRC HOSTNAME 
LESSOPEN USER HOSTTYPE HOME OLDPWD TERM MACHTYPE LOGNAME PATH SHELL MAIL LANG
--------------------------------------------------------------------------------
./exe
_ QTDIR LS_COLORS SHLVL KDEDIR HISTSIZE OSTYPE PWD SSH_TTY INPUTRC HOSTNAME 
LESSOPEN USER HOSTTYPE HOME OLDPWD TERM MACHTYPE LOGNAME PATH SHELL MAIL LANG
--------------------------------------------------------------------------------
./top
_ QTDIR LS_COLORS SHLVL KDEDIR HISTSIZE OSTYPE PWD SSH_TTY INPUTRC HOSTNAME 
LESSOPEN USER HOSTTYPE HOME OLDPWD TERM MACHTYPE LOGNAME PATH SHELL MAIL LANG
사실 이 것은 당연한 것입니다. (아시는 분에게는 너무도 당연한 내용이지요:-) my로 선언된 %ENV는 그 블록 안에서만 접근이 됩니다. 만일 system함수가 아니라 다른 서브루틴이 호출되어졌다 하더라도, 서브루틴 안에서 조차도 외부블록에서 my로 선언된 내용은 읽을 수 없으니까요.
my를 local로 바꾸면 원하던 바가 이루어집니다.

....
if( -x './exe' ) {
        local %ENV;
        %ENV = qw( aa 1 bb 2 cc 3 dd 4 );
        system('./exe');
}
이 경우 출력되는 내용은,

--------------------------------------------------------------------------------
./top
_ QTDIR LS_COLORS SHLVL KDEDIR HISTSIZE OSTYPE PWD SSH_TTY INPUTRC HOSTNAME 
LESSOPEN USER HOSTTYPE HOME OLDPWD TERM MACHTYPE LOGNAME PATH SHELL MAIL LANG
--------------------------------------------------------------------------------
./exe
aa dd bb cc
--------------------------------------------------------------------------------
./top
_ QTDIR LS_COLORS SHLVL KDEDIR HISTSIZE OSTYPE PWD SSH_TTY INPUTRC HOSTNAME 
LESSOPEN USER HOSTTYPE HOME OLDPWD TERM MACHTYPE LOGNAME PATH SHELL MAIL LANG
입니다. 부모 프로세스에서 설정한 %ENV 내용이 자식 프로세스의 %ENV에 반영이 되었고, 블록 내에서 local로 선언했기 때문에 블록 외부에서는 변화없이 %ENV의 내용을 지킬 수 있었습니다.

때로 local과 my의 선택은 이처럼 불명확할 수도 있습니다. 만일 선택이 어려운 경우라면, 위에서처럼 간단한 스크립트를 만들어 실행해 보시기 바랍니다. 

Comments