Perl 프로그램들의 동작 방식을 설정하는 기법들.
-
- 1. Mastering Perl 에서
-
-
- 1.1. 하지 말아야 할 일 (Things Not to Do)
-
-
- 1.1.1. 코드를 별도의 파일에 저장 (Code in a Separate File)
-
1.2. 더 나은 방법들 (Better Ways)
-
-
- 1.2.1. 환경 변수 (Environment Variables)
-
- 1.2.2. 특별한 환경 변수 (Special Environment Variables)
-
- 1.2.3. 별도의 출력 (Turning on Extra Output)
-
1.3. 명령행 스위치 (Command-line Switches)
-
-
- 1.3.1. -s 스위치 (The -s Switch)
-
- 1.3.2. Getopt::Std
-
- 1.3.3. Getopt::Long
-
1.4. 설정 파일 (Configuration Files)
-
-
- 1.4.1. ConfigReader::Simple
-
- 1.4.2. Config::IniFiles
-
- 1.4.3. Config::Scoped
-
- 1.4.4. AppConfig
-
- 1.4.5. 그 외의 설정 포맷 (Other Configuration Formats)
-
1.5. 스크립트를 여러 가지 이름으로 실행 (Scripts with a Different Name)
-
- 1.6. 대화식 / 비대화식 프로그램 (Interactive and Noninteractive Programs)
-
- 1.7. perl의 Config 모듈 (perl's Config)
-
-
- 1.7.1. 여러가지 운영체제 (Different Operating Systems)
-
1.8. 읽어볼 글들 (Further Reading)
-
1. Mastering Perl 에서
[Mastering Perl: Configuring Perl Programs]의 내용 요약.
프로그램의 동작을 조금씩 바꾸기 위해서 여러 가지 설정값을 사용한다. 이 설정값을 변경하기 위해서 사용자가 프로그램을 직접 수정하게 되는 일은 최대한 피해야 한다.
1.1. 하지 말아야 할 일 (Things Not to Do)
프로그램 내에 변수들을 잔뜩 집어넣고 사용자가 직접 그 변수의 값을 수정해서 사용하게 하지 말라.
- 수정하면 안 될 코드까지 수정할 수 있다.
- 오타 등의 이유로 문법 에러를 일으킬 수 있다.
- 프로그램을 여러 기계에 설치하여 사용할 때 서로 다른 버전을 사용하게 될 수도 있고, 이 경우 프로그램을 업데이트할 때마다 각각의 버전들을 일일이 수정해야 한다.
#!/usr/bin/perl
use strict;
use warnings;
my $Debug = 0;
my $Verbose = 1;
my $Email = 'alice@example.com';
my $DB = 'DBI:mysql';
데이타에 이름을 붙여서 재사용하길 원한다면 constant 프라그마를 사용한다.
use constant PI => 3.14159;
my $radius = 1;
my $circumference = 2 * PI * $radius;
Readonly 모듈을 사용할 수도 있다.
use Readonly;
Readonly::Scalar my $Pi => 3.14159;
Readonly::Array my @Fibonacci => qw( 1 1 2 3 5 8 13 21 );
Readonly::Hash my %Natural => ( e => 2.72, Pi => 3.14, Phi => 1.618 );
Perl 5.8(1) 이후에서는 패키지 이름 부분의 두번째 레벨을 생략할 수 있다.
use 5.8;
use Readonly;
Readonly my $Pi => 3.14159;
Readonly my @Fibonacci => qw(1 1 2 3 5 8 13 21 );
Readonly my %Natural => ( e => 2.72, Pi => 3.14, Phi => 1.618 );
1.1.1. 코드를 별도의 파일에 저장 (Code in a Separate File)
설정과 관련된 코드를 별도의 파일로 작성하고 메인 프로그램에서 그 파일을 읽어오게 하는 방법 - 조금 세련된 방법이긴 하나 여전히 좋지 않다.
config.pl 에 설정에 관련된 코드를 넣는 예:
- 스코프 문제 때문에 렉시컬 변수를 사용할 수 없다.
- use vars 선언을 메인 프로그램을 컴파일하기 전에 처리해야 하므로 BEGIN 블럭에 넣어야 한다.
use vars qw( $Debug $Verbose $Email $DB );
$Debug = 0;
$Verbose = 1;
$Email = 'alice@example.com';
$DB = 'DBI:mysql';
#!/usr/bin/perl
use strict;
use warnings;
BEGIN { require "config.pl"; }
1.2. 더 나은 방법들 (Better Ways)
1.2.1. 환경 변수 (Environment Variables)
Perl 프로그램 내에서 %ENV 해쉬를 사용하여 환경 변수에 접근할 수 있다.
환경 변수들의 이름과 값을 출력하는 프로그램의 예:
#!/usr/bin/perl
print "Content-type: text/plain\n\n" if $ENV{REQUEST_METHOD};
foreach my $key ( sort keys %ENV )
{
printf "%-20s %s\n", $key, $ENV{$key};
}
1.2.2. 특별한 환경 변수 (Special Environment Variables)
Perl 바이너리가 사용하는 환경변수들.
- PERL5OPT
- perl을 실행할 때 명령행 인자로 이 변수의 값을 준 것처럼 동작한다.
% export PERL5OPT=w
- PERL5LIB
- use lib 지시자의 역할. 모듈을 찾을 곳을 지정한다.
- /모듈 참조
% export PERL5LIB=/Users/brian/lib/perl5
1.2.3. 별도의 출력 (Turning on Extra Output)
디버그를 할 때만 추가로 자세한 정보를 출력시키는 경우.
- 코드를 따로 고치지 않고 환경 변수를 수정하는 것만으로 이런 동작을 지시
$ DEBUG=1 ./program.pl
$ export DEBUG=1
$ ./program.pl
펄 코드 쪽에서는 이 환경 변수의 값을 읽음:
#!/usr/bin/perl
use strict;
use warnings;
my $Debug = $ENV{DEBUG};
my $Verbose = $ENV{VERBOSE};
...
print "Starting processing\n" if $Verbose;
...
warn "Stopping program unexpectedly" if $Debug;
환경 변수를 정의하지 않은 채 실행할 경우 초기화되지 않은 값을 사용한다는 경고가 나온다. 이를 막기 위해서 디폴트값을 지정:
my $Debug = $ENV{DEBUG} || 0;
my $Verbose = $ENV{VERBOSE} || 1;
"||" 연산자를 쓸 경우 왼쪽 피연산자의 값으로 0을 받았을 때 false 판정되므로 문제가 된다. (위의 경우 VERBOSE가 제대로 처리되지 않는다) "정의되었는가 아닌가"만을 판단하기 위해서는 defined를 사용:
my $Debug = defined $ENV{DEBUG} ? $ENV{DEBUG} : 0;
my $Verbose = defined $ENV{VERBOSE} ? $ENV{VERBOSE} : 1;
Perl 5.10(2)에서는 defined-or(//) 연산자를 제공한다.
my $Verbose = $ENV{VERBOSE} // 1;
변수값들이 서로 영향을 미치는 경우 - DEBUG가 켜져 있으면 VERBOSE도 자동으로 켜지는 예:
my $Debug = $ENV{DEBUG} || 0;
my $Verbose = $ENV{VERBOSE} || $ENV{DEBUG} || 0;
1.3. 명령행 스위치 (Command-line Switches)
명령행 인자 형태로 주어지는 스위치를 다룰 수 있는 약 90가지 CPAN 모듈 중에 몇 가지.
1. 하이픈 + 단일 문자 형태
% foo -i -t -r
2. 하이픈 + 단일 문자 + 값(필수 또는 옵션) 형태. 스위치와 값 사이에 구분자가 있을 수 있음
% foo -i -t -d/usr/local
% foo -i -t -d=/usr/local
% foo -i -t -d /usr/local
3. 단일 문자 스위치 여러개가 하나의 그룹을 이룬 형태.
% foo -itr
4. 하이픈 + 복수 문자 + 값(필수 또는 옵션)
% foo -debug -verbose=1
5. 더블 하이픈 + 복수 문자 형태. 하이픈 + 단일 문자, 단일 문자들의 그룹
% foo --debug=1 -i -t
% foo --debug=1 -it
6. 스위치의 끝을 알리는 더블 하이픈. 이 더블 하이픈 뒤에 나오는 인자는 하이픈으로 시작한다 해도 스위치가 아님을 알려준다.
% foo -i -t --debug -- --this_is_an_argument
7. 동일한 역할을 하는 스위치가 여러 다른 형태로 존재
% foo -d
% foo --debug
8. 다양한 기호로 스위치임을 표시하는 경우. 아예 기호를 사용하지 않는 경우 등
% foo input=bar.txt --line 10-20
1.3.1. -s 스위치 (The -s Switch)
- 프로그램 스위치를 패키지 변수로 변환
- 다음 두 가지 형태를 지원
- 싱글 하이픈 + 문자열
- 더블 하이픈 + 문자열 ( 이 경우 싱글 하이픈 + 하이픈으로 시작하는 문자열의 형태로 인식 )
#!/usr/bin/perl -sw
use strict;
use vars qw( $a $abc );
print "The value of the -a switch is [$a]\n";
print "The value of the -abc switch is [$abc]\n";
- 값이 없는 스위치는 값을 1로 설정한다.
- "스위치=값" 형태로 값을 주면 그 값으로 설정한다.
% perl -s ./perl-s-abc.pl -abc=fred -a
The value of the -a switch is [1]
The value of the -abc switch is [fred]
- 더블 하이픈을 사용할 경우는 변수의 이름이 하이픈으로 시작하게 되므로, strict 를 사용할 경우 refs 를 꺼서 심볼릭 레퍼런스를 허용해 주어야 한다.
#!/usr/bin/perl -s
use strict;
{
no strict 'refs';
print "The value of the --debug switch is [${'-debug'}]\n";
print "The value of the --help switch is [${'-help'}]\n";
}
% perl -s ./perl-s-debug.pl --debug=11
The value of the --debug switch is [11]
The value of the --help switch is []
코어 모듈.
주요 함수 : getopt, getopts
- getopt
- getopt( 스위치 문자들로 이뤄진 스트링, 스위치 문자를 키로 하고 스위치 값을 값으로 하는 해쉬의 레퍼런스 )
- 스위치 뒤에 값이 오면 값을 할당. 그렇지 않으면 아무 값도 할당하지 않음
- 두번째 인자가 없을 경우는 패키지 변수에 할당 ( $opt_스위치문자 ) - 권장하지 않음
#!/usr/bin/perl
use strict;
use Getopt::Std;
getopt('dog', \ my %opts );
print <<"HERE";
The value of
d $opts{d}
o $opts{o}
g $opts{g}
HERE
$ perl getopt-std.pl -d 1
The value of
d 1 <-- 값이 할당된다
o
g
$ perl getopt-std.pl -d
The value of
d <-- 스위치를 켰지만 값이 할당되지 않는다
o
g
- getopts
- getopts( 문자열, 해쉬 레퍼런스 )
- 값이 필요없는 스위치 지원 ( 켜져 있으면 1로 세팅 )
- 값이 필요한 스위치는 문자 뒤에 콜론을 붙여서 표시
#!/usr/bin/perl
use Getopt::Std;
getopts('dog:', \ my %opts );
print <<"HERE";
The value of
d $opts{d}
o $opts{o}
g $opts{g}
HERE
$ perl getopts-std.pl -g foo -d
The value of
d 1
o
g foo
값이 필요한 스위치 뒤에 값을 넣지 않으면 잘못된 결과
% ./getopts.pl -g -d -o <-- "-d"는 -g 스위치의 값으로 간주된다
The value of
d
o 1
g -d
반대로 값이 필요없는 스위치 뒤에 값을 넣으면 그 시점에서 getopts의 인자처리가 종료됨
$ perl getopts-std.pl -d foo -g bar -o
The value of
d 1
o
g
1.3.3. Getopt::Long
코어 모듈.
- 단일 문자 스위치
- 복수 문자 스위치
- 더블 하이픈으로 시작하는 스위치
- alias 지원
- GetOptions ( 키-값 쌍의 리스트 )
- 키 - 스위치 이름
- 값 - 해당 스위치의 값을 담을 변수의 레퍼런스
#!/usr/bin/perl
use Getopt::Long;
my $result = GetOptions(
'debug|d' => \ my $debug,
'verbose|v' => \ my $verbose,
);
print <<"HERE";
The value of
debug $debug
verbose $verbose
HERE
- 'debug|d' - '|'로 구분하여 alias 지정가능
주인장 보충:
- 스위치 이름이 "debug"일 때는, "d", "de", "deb", "debu" 까지가 다 자동으로 인식이 된다. 따라서 굳이 "d"를 명시해 줄 필요는 없다.
- 만일 "delay"라는 스위치도 존재한다면, "de"까지는 두 스위치에 겹치기 때문에 인식하지 않는다.
- alias는 여러 개를 병기할 수도 있고, 두 글자 이상이어도 된다. 예: "debug|a|bc"
$ perl getoptions-v.pl -verbose
The value of
debug
verbose 1
$ perl getoptions-v.pl -v
The value of
debug
verbose 1
$ perl getoptions-v.pl -v -d
The value of
debug 1
verbose 1
$ perl getoptions-v.pl -v -debug
The value of
debug 1
verbose 1
$ perl getoptions-v.pl -v --debug
The value of
debug 1
verbose 1
- 값을 주어야 하는 스위치는 이름 뒤에 "="를 붙여서 표시. =s는 스트링. =i는 정수.
#!/usr/bin/perl
use Getopt::Long;
my $result = GetOptions(
"file=s" => \ my $file,
"line=i" => \ my $line,
);
print <<"HERE";
The value of
file $file
line $line
HERE
$ perl getopt-long-args.pl -line=-9
The value of
file
line -9
$ perl getopt-long-args.pl -line=9.9
Value "9.9" invalid for option line (number expected)
The value of
file
line
- 여러 개의 값을 받는 스위치의 경우는 "@"로 표시
#!/usr/bin/perl
use Getopt::Long;
my $result = GetOptions(
"file=s@" => \ my @files,
);
{
local $" = ", ";
print <<"HERE";
The value of
file @files
HERE
}
$ perl getopt-long-mult.pl --file foo --file bar
The value of
file foo, bar
1.4. 설정 파일 (Configuration Files)
1.4.1. ConfigReader::Simple
file=foo.dat
line=453
field value
field2 = value2
long_continued_field This is a long \
line spanning two lines
#!/usr/bin/perl
use ConfigReader::Simple;
my $config = ConfigReader::Simple->new(
"configreader-simple.txt" );
die "Could not read config! $ConfigReader::Simple::ERROR\n"
unless ref $config;
print "The line number is ", $config->get( "line" ), "\n";
1.4.2. Config::IniFiles
[Debugging]
;ComplainNeedlessly=1
ShowPodErrors=1
[Network]
email=brian.d.foy@gmail.com
[Book]
title=Mastering Perl
publisher=O'Reilly Media
author=brian d foy
#!/usr/bin/perl
use Config::IniFiles;
my $file = "mastering_perl.ini";
my $ini = Config::IniFiles->new(
-file => $file
) or die "Could not open $file!";
my $email = $ini->val( 'Network', 'email' );
my $author = $ini->val( 'Book', 'author' );
print "Kindly send complaints to $author ($email)\n";
1.4.3. Config::Scoped
- INI와 비슷한데, 섹션을 중첩할 수 있으며, 한 키에 여러 개의 값을 지정할 수 있음
book {
author = {
name="brian d foy";
email="brian.d.foy@gmail.com";
};
title="Mastering Perl";
publisher="O'Reilly Media";
}
#!/usr/bin/perl
use Config::Scoped;
my $config = Config::Scoped->new( file => 'config-scoped.txt' )->parse;
die "Could not read config!\n" unless ref $config;
print "The author is ", $config->{book}{author}{name}, "\n";
- 명령행 옵션, 설정 파일, 환경 변수, CGI 파라메터 등을 일괄적으로 처리 가능
- 설정파일의 경우 ConfigReader::Simple에서 지원하는 라인 기반 포맷, INI 포맷, 기타 다양한 포맷 지원
- INI파일을 사용하는 예
- 다양한 포맷을 지원하기 때문에, 사용가능한 스위치와 스위치에 할당될 수 있는 값의 형태 등을 알려줘야 한다.
- Getopt::Long에서 쓰는 포맷 문법을 사용.
- INI 포맷의 경우 섹션과 키의 이름을 flatten함
#!/usr/bin/perl
use AppConfig;
my $config = AppConfig->new;
$config->define( 'network_email=s' );
$config->define( 'book_author=s' );
$config->define( 'book_title=s' );
$config->define( 'book_publisher=s' );
$config->file( 'config.ini' );
my $email = $config->get( 'network_email' );
my $author = $config->get( 'book_author' );
print "Kindly send complaints to $author ($email)\n";
- args() 함수를 써서 @ARGV에 들어온 명령행 옵션들을 Getopt::Long을 이용하여 처리
#!/usr/bin/perl
use AppConfig;
my $config = AppConfig->new;
$config->define( 'network_email=s' );
$config->define( 'book_author=s' );
$config->define( 'book_title=s' );
$config->define( 'book_publisher=s' );
$config->file( 'config.ini' );
$config->args();
my $email = $config->get( 'network_email' );
my $author = $config->get( 'book_author' );
print "Kindly send complaints to $author ($email)\n";
$ perl appconfig-args.pl
Kindly send complaints to brian d foy (brian.d.foy@gmail.com)
$ perl appconfig-args.pl -network_email bdfoy@cpan.org <-- network_email 스위치를 override
Kindly send complaints to brian d foy (bdfoy@cpan.org)
1.4.5. 그 외의 설정 포맷 (Other Configuration Formats)
1.5. 스크립트를 여러 가지 이름으로 실행 (Scripts with a Different Name)
하나의 프로그램을 심볼릭 링크 등을 사용해서 여러 가지 서로 다른 이름을 붙인 후, 실행할 때 사용한 이름이 뭐냐에 따라서 각각 다르게 동작하게 할 수 있다. 이 때 실행할 때 사용한 이름은 $0 변수에 저장된다.
if( $0 eq ... ) { ... do this init ... }
elsif( $0 eq ... ) { ... do this init ... }
...
else { ... default init ... }
이름을 다르게 붙이는 방법 대신에, 또다른 프로그램 안에서 환경 변수와 스위치 등을 적절하게 설정한 후 본래의
프로그램을 호출하도록 하는 방법도 있다
DEBUG=0
VERBOSE=0
DBI_PROFILE=2
./program -n some_value -m some_other_value
1.6. 대화식 / 비대화식 프로그램 (Interactive and Noninteractive Programs)
프로그램이 터미널 등에서 대화식으로 실행될 때와, 스케줄러 등에 의해서 비대화식으로 실행될 때 동작을 조금 다르게 하고 싶은 경우.
- 파일 테스트 연산자 -t 를 사용하여 표준입력과 표준출력이 터미널에 연결되어 있는지를 검사
$ perl -le 'print "Interactive!" if( -t STDIN and -t STDOUT )'
Interactive!
use IO::Interactive qw(is_interactive);
my $can_talk = is_interactive();
print "Hello World!\n" if $can_talk;
- interactive - 대화식으로 실행되는 중이면 STDOUT 파일핸들을 반환. 아니면 null 파일핸들 반환
use IO::Interactive qw(interactive);
print { interactive() } "Hello World!\n";
1.7. perl의 Config 모듈 (perl's Config)
perl 바이너리를 컴파일했을 때 사용됐던 옵션들에 대한 정보를 %Config 해쉬에 저장
#!/usr/bin/perl
use Config;
print "Send complaints to $Config{cf_email}\n";
print "I was compiled on $Config{myhostname}.$Config{mydomain}\n";
print "has thread support\n" if $Config{usethreads};
1.7.1. 여러가지 운영체제 (Different Operating Systems)
- $^O , $Config{'osname'} 현재 실행되고 있는 OS 이름
- $Config{'archname'} - 좀 더 상세한 정보
하나의 모듈이, 운영체제 이름에 따라서 서로 다른 모듈을 내부적으로 불러들이는 예 ( File::Spec )
package File::Spec;
use strict;
use vars qw(@ISA $VERSION);
$VERSION = '0.87';
my %module = (MacOS => 'Mac',
MSWin32 => 'Win32',
os2 => 'OS2',
VMS => 'VMS',
epoc => 'Epoc',
NetWare => 'Win32',
dos => 'OS2',
cygwin => 'Cygwin');
my $module = $module{$^O} || 'Unix';
require "File/Spec/$module.pm";
@ISA = ("File::Spec::$module");
1;
1.8. 읽어볼 글들 (Further Reading)
컴퓨터분류