[첫화면으로]Perl/Configuring

마지막으로 [b]

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';

#### DON'T EDIT BEYOND THIS LINE !!! ###

데이타에 이름을 붙여서 재사용하길 원한다면 constant 프라그마를 사용한다.
use constant PI => 3.14159;

my $radius = 1;
my $circumference = 2 * PI * $radius;

Cpan: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)

설정과 관련된 코드를 별도의 파일로 작성하고 메인 프로그램에서 그 파일을 읽어오게 하는 방법 - 조금 세련된 방법이긴 하나 여전히 좋지 않다.1

config.pl 에 설정에 관련된 코드를 넣는 예:
# config.pl
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 바이너리가 사용하는 환경변수들.

% export PERL5OPT=w   # -w 스위치를 켠다.
% 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
# perl-s-abc.pl
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";
% 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]
#!/usr/bin/perl -s
# perl-s-debug.pl
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 []

1.3.2. Getopt::Std

코어 모듈.

주요 함수 : getopt, getopts
#!/usr/bin/perl
# getopt-std.pl
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
#!/usr/bin/perl
# getopts-std.pl

use Getopt::Std;

getopts('dog:', \ my %opts );   # -g 스위치는 값이 필요함

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

코어 모듈.2

#!/usr/bin/perl
# getoptions-v.pl

use Getopt::Long;

my $result = GetOptions(
    'debug|d'   => \ my $debug,
    'verbose|v' => \ my $verbose,
    );

print <<"HERE";
The value of
    debug               $debug
    verbose             $verbose
HERE
주인장 보충:

$ 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
#!/usr/bin/perl
# getopt-long-args.pl

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
# getopt-long-mult.pl

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

# configreader-simple.txt
file=foo.dat
line=453
field value
field2 = value2
long_continued_field This is a long \
    line spanning two lines

#!/usr/bin/perl
# configreader-simple.pl

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
# config-ini.pl

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

book {
    author = {
        name="brian d foy";
        email="brian.d.foy@gmail.com";
        };
    title="Mastering Perl";
    publisher="O'Reilly Media";
}

#!/usr/bin/perl
# config-scoped.pl

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";

1.4.4. AppConfig

#!/usr/bin/perl
# appconfig-ini.pl

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";

#!/usr/bin/perl
# appconfig-args.pl

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 ... }

이름을 다르게 붙이는 방법 대신에, 또다른 프로그램 안에서 환경 변수와 스위치 등을 적절하게 설정한 후 본래의 프로그램을 호출하도록 하는 방법도 있다

#!/bin/sh

DEBUG=0
VERBOSE=0
DBI_PROFILE=2

./program -n some_value -m some_other_value

1.6. 대화식 / 비대화식 프로그램 (Interactive and Noninteractive Programs)

프로그램이 터미널 등에서 대화식으로 실행될 때와, 스케줄러 등에 의해서 비대화식으로 실행될 때 동작을 조금 다르게 하고 싶은 경우.

$ 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;
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)

하나의 모듈이, 운영체제 이름에 따라서 서로 다른 모듈을 내부적으로 불러들이는 예 ( Perldoc: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', # Yes, File::Spec::Win32 works on NetWare.
              dos     => 'OS2',   # Yes, File::Spec::OS2 works on DJGPP.
              cygwin  => 'Cygwin');


my $module = $module{$^O} || 'Unix';

require "File/Spec/$module.pm";
@ISA = ("File::Spec::$module");

1;

1.8. 읽어볼 글들 (Further Reading)

이름:  
Homepage:
내용:
 


컴퓨터분류
각주:
1. UseModWiki소스수정도 이렇게 되어 있습죠;;
2. 더 자세한 내용은 /Getopt-Long 참조
찾아보기:
Perl   
  5.10   2
  5.8   1
   

마지막 편집일: 2012-2-11 12:25 am (변경사항 [d])
4119 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기