전종필
die함수를 사용할 때 인수를 주지 않거나, 인수의 맨 뒤에 "\n" 문자를 붙여주지 않으면 "... at myprog.pl line 123"과
같은 내용을 출력합니다.
이 내용은 디버깅을 할 때 상당히 유용한 내용입니다. 출력된 내용에 따라, 해당 파일의 해당 라인을 들여다 보면
되니까요.
하지만, 이 내용이 실질적인 에러 발생지점이라고 보기가 어려운 때가 많이 있습니다. 다음 예를 보시기 바랍니다. (다음
프로그램이 꽤 긴 것이라고 생각합시다.)
# prog.pl
require 'lib.pl';
my $file = shift @ARGV;
my $txt = readFile($file); # 라이브러리에 있는 서브루틴
my( $logfile ) = ( $text =~ /\blogfile=(\S+)/ );
my( $textfile ) = ( $text =~ /\btextfile=(\S+)/ );
# 중간 500줄 생략 ^^
my $logtxt = readFile($logfile);
# 중간 300줄 생략 ^^
my $texttxt = readFile($logfile);
# 이러고 저러고...
# 끝.
다음은 라이브러리입니다.
# lib.pl
sub readFile {
my $file = shift;
my $txt;
if( open(FILE,$file) ) {
local $/ = undef;
$txt = ;
close FILE;
}
else {
die "파일읽기 오류($file): $!";
}
$txt;
}
만일 prog.pl을 실행하던 중 파일 이름이 틀리거나, 잘 못된 이름이어서 readFile
서브루틴에서 open이 실패된다면, 프로그램은 다음과 유사한 내용을 출력하고 종료합니다.
파일읽기 오류(filename): No such file or directory at lib.pl line 11.
내용은 prog.pl이 아닌 lib.pl에서 실제로 die가 호출된 지점을 알려줍니다. 하지만,
우리가 원하는 내용은
my $txt = readFile($file);
나
my $logtxt =
readFile($logfile);
, 혹은
my $texttxt = readFile($logfile);
이
호출된 어떤 지점의 라인 번호일 것입니다. 그 것을 알아내기 위해서 caller라는
함수를 사용합니다. 그리고 lib.pl을 다음과 같이 수정합니다.(
else { die.. }
부분)
# lib.pl
sub readFile {
my $file = shift;
my $txt;
if( open(FILE,$file) ) {
local $/ = undef;
$txt = ;
close FILE;
}
else {
my( $package, $filename, $linenum, $subroutine ) = caller; # ``caller 0''과 같음
die "파일읽기 오류(File: $file): $! at $filename line $linenum\n";
}
$txt;
}
caller함수를 호출하면 위와 같이 현재의 서브루틴을 호출한 부분에 대한 정보를
반환합니다.
만일 여러 단계의 서브루틴 호출이 있었고, 그 호출 내용을 모두 알아야 한다면, caller에 인수로 0부터 1씩
증가시켜가며,
else {
my $at;
my $i = 0;
my( $package, $filename, $linenum, $subroutine )
while( ( $package, $filename, $linenum, $subroutine ) = caller($i++) ) {
$at .= " /$filename($linenum)";
}
die "파일읽기 오류(File: $file): $! at $at\n";
}
하면, 모든 파일이름과 라인 번호를 얻을 수 있습니다.