perl

概要 プログラム サブルーチン
演算子 算術演算子 文字列演算子 ファイル検査演算子
パターン・マッチ パターン・マッチ 正規表現

変数 宣言と参照 配列 リスト ハッシュ
システム変数 特殊変数 定義済変数 特殊シンボル
リファレンス 作成 デリファレンス 関数のリファレンス
組込み関数 文字列処理操作 リスト操作 連想配列操作 システム関数
ファイル、ディレクトリ操作 eval エラー処理
文字と文字列 プレフィックス 引用符 エスケープ文字
入出力 ファイル・ハンドル 入出力切り替え ヒアドキュメント
モジュール スケルトン 作成 参照 FTP
オブジェクト指向 生成 継承

環境 オプション perl 4 VS 5 ツール
その他 デバッグ FAQ 参考書
予約語 略語集 用語集 リンク集
CGI CGI 環境変数 ブラウザ情報
マニュアル online マニュアル perl5.0 FTP.pm スタイルガイド
パッケージとモジュール




概要

perl (Practical Extraction and Report Language) は、インタプリタであり、またスクリプト言語でもあります。
もちろんオープンソースですので、ここからダウンロードして自由につかえます。

プログラムをファイルに格納する場合は、拡張子として .pl を使います。
ここで "Hello world !" を印刷するプログラムを考えてみましょう。

#!/usr/local/bin/perl -w
use strict;                        文法チェックを厳格にする 

print "Hello world !\n";

[ 実行結果 ] 
> perl hello.pl
Hello world !  

動作
if 条件 {文}; 条件が真なら文を実行
if (! open(FOUT,">$out_file"))  {
   &err_out("can\'t open $out_file");
   exit(3);
} 
式 if 条件; 条件が真なら式を実行 print "file is empty\n" if -z $filenm;
式 unless 条件; 条件が偽なら式を実行 $reject++,next unless $good;
式 while 条件; 条件が真の間、式を実行 print $line while ($line = <>);
式 until 条件; 条件が偽の間、式を実行 $reject++ unless $good;
while (条件) {
  ループ本体
}
条件が真の間、
ループ本体を実行
while ($data eq $prev) {
   $prev = $data;
   $data =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/gei;
}
for (式1; 式2; 式3) {
  ループ本体
}
式2 が真の間、
ループ本体を実行
@array = ('aaa','bbb','ccc');
for ($i=0; $i<=$#array; $i++) {
   print $array[$i],"\n";
}
foreach 変数 (リスト) {
  ループ本体
}
変数に値の間、
ループ本体を実行
@languages = ('Eng','Jap','Ger');
foreach $name (@languages) {
   print $name,"\n";
} 

foreach (@array) { print "$_ \n"; }
式1;
while (式2) {
  ループ本体
} continue {
  式3;
}
上記 for 文と同じ
$longest = 0;
while ($line = <>) {
   chomp $line;
   $len =length($line);
   if ($longest < $len) {
      $longest = $len;
   }
}
print "Longest line is $longest\n";
do ブロック while 条件; ブロック実行後、条件が真の間
ブロックを実行

do ブロック until 条件; ブロック実行後、条件が偽の間
ブロックを実行

& サブルーチン(); サブルーチンよびだし & mk_date();
do ファイル名; ファイルを perl プログラムとして実行
goto ラベル; ラベルにとぶ goto notfound;
next ラベル; ループを出て continue ブロックを
実行して次のループを実行します
ラベルでループブロックを指定できます
while (<>) {
   : 
    next if ($cnt <7); 
}
redo; 現在のループをやり直します redo;
last; ループを中止します。c の break と同じ
while (<>) {
   : 
    last if ($cnt > $MAX); 
}
continue ブロック while,until で使え
各ループの最後で実行される
continue;
exit(終了コード); 終了コードで実行を終わる exit(10);
# 文字列 コメント # This is a comment

プログラム

サブルーチン

perl のサブルーチンの戻り値は通常 1 が成功、0 が失敗です。

項目 書式
定義 
sub 名前 {
   ブロック 定義
}

引数は @_ 
または $_[0] ... $_[n]

局所変数(レキシカル変数)は my (変数リスト);

また @_ で引数を受ける場合は、
レキシカル変数が1つでも括弧で囲む必要があります

my $aaa=1;             宣言して初期化する

my ($arg1,$arg2) = @_ ;      引数のセット
引数が @a1,@a2 の場合は、受け渡しが複雑(参照)

& sb_call(\@a1,\@a2);

sub sb_call {
   my ($arg1,$arg2) = @_ ;
   my (@p__1,@p__2);

   @p__1 = @$arg1;          元の配列と同じ
   @p__2 = @$arg2;          元の配列と同じ

サンプル t_sbb.pl
    
sub prt_max2 {
   my ($max,$min)=@_;      引数を局所変数に設定
   $max = $min    if $min > $max;
   print " $max\n"
}

sub prt_max { $max = $_[0]; $max = $_[1] if $_[1] > $max; print " $max\n" return $max; 戻り値 }
参照 & サブルーチン名(引数列); $mmm = &prt_max(12,345);




演算子

算術演算子

演算子 説明
++,-- インクリメント、デクリメント $cnt++;
** べき乗 $cnt**;
!,~,- 真偽否定、ビット反転、マイナス $a++ if (! $a);
*,/,%,x 乗、除、剰余、繰り返し $rem = int($dno % $SZ_ITEM);
剰余は int 変換すること
+,- 加、減 $a = $c + $b;
<<,>> ビットシフト $s = $a << 2;
<,>,<=,>= 比較 if ($cnt > $end) $ExitValue = 0;
==,!=,<=> 比較 if (($len == 0) || ($len == 1)) next;
& ビットごとの and $bit = $bit_a & $bit_b;
|,^ ビットごとの or,ex or $bit = $bit_a | $bit_b;
&& and $c ++ if ($a && $b);
|| or $c ++ if ($a || $b);
..,... 範囲演算子 print $a(1 .. 3)
? : 条件演算子 $max = ($max>$cur) ? $max : $cur
=,+=,-= 代入演算子 $end = $start + $MAX;
, コンマ演算子 $a=1,$b=2,$c=3;




文字列演算子

演算子 説明
=~,!~ パターン指定 $a = $b =~ /pat/;
$c !~ /pat/;
.  文字列結合 $c = $a . $b;
lt,gt,le,ge,eq,ne,cmp  文字列比較
print "data1 equal data2\n"   if ($data1 eq $data2);




ファイル検査演算子

演算子 説明
-r 実効 uid/gid で読み込み可能 print "読み込み可\n" if -r $filenm;
-w 実効 uid/gid で書き込み可能 print "書き込み可\n" if -w $filenm;
-x 実効 uid/gid で実行可能 print "実行可\n" if -x $filenm;
-o 所有者が実効 uid print "所有\n" if -o $filenm;
-R 実 uid/gid で読み込み可能 print "読み込み可\n" if -R $filenm;
-W 実 uid/gid で書き込み可能 print "書き込み可\n" if -W $filenm;
-X 実 uid/gid で実行可能 print "実行可\n" if -X $filenm;
-O 所有者が実 uid print "所有\n" if -O $filenm;
-e ファイルが存在する print "ファイルが存在する\n" if -e $filenm;
-z ファイルが空 print "ファイルが空\n" if -z $filenm;
-s ファイルが空でない(サイズを返す) print "ファイルが空でない\n" if -s $filenm;
-f 普通のファイル print "普通のファイル\n" if -f $filenm;
-d ディレクトリ print "ディレクトリ\n" if -d $filenm;
-l シンボリックリンク print "シンボリックリンク\n" if -l $filenm;
-p 名前つきパイプ (FIFO) print "名前つきパイプ\n" if -p $filenm;
-s ソケット print "ソケット\n" if -s $filenm;
-b ブロックデバイス print "ブロックデバイス\n" if -b $filenm;
-c キャラクタデバイス print "キャラクタデバイス\n" if -c $filenm;
-u setuid ビットが立っている print "setuid ビットオン\n" if -u $filenm;
-g setgid ビットが立っている print "setuid ビットオン\n" if -g $filenm;
-k sticky ビットが立っている print "sticky ビットオン\n" if -k $filenm;
-t ファイルハンドルが tty である print "tty\n" if -t $filenm;
-T テキストファイル print "テキストファイル\n" if -T $filenm;
-B バイナリファイル print "バイナリファイル\n" if -B $filenm;
-M 最終更新時刻からスクリプト開始
までの日数
print "普通のファイル\n" if -f $filenm;
-A 最終アクセス時刻からスクリプト開始
までの日数
print "普通のファイル\n" if -f $filenm;
-C 最終 i ノード更新時刻からスクリプト
開始までの日数
print "普通のファイル\n" if -f $filenm;




機能

パターン・マッチ

マッチ XXX ~ /正規表現/修飾子; if (STRING =~ /PATTERN/) ...;
非マッチ XXX !~ /正規表現/修飾子; if (STRING !~ /PATTERN/) ...;
置換 s/正規表現/置換文字/修飾子; $var =~ s/PATTERN/REPLACEMENT/;
修飾子
g    繰り返してマッチ
i    英字の大文字、小文字を区別しない
m    文字列を複数行として扱う
o    PATTERNのコンパイルを 1回だけにする
s    ワイルドカードのドット( . )が改行にもマッチするようにする
x    パターン内の空白を無視し、# 以降の文字列をコメントとします
e    式の右側の評価を行なう
ee   式の右側の評価を行い、実行後の戻り値を再度評価する
$var =~ s/[A-Z]/[a-z]g

マッチの場合、パターン中のグループは変数 $1,$2,.... に残ります。

量指定子には、欲張り指定子と非欲張り指定子があります。 欲張り指定子は、"*,+,?,{}" などで、 非欲張り指定子は、"*?,+?,??,{}?" などです。

[例 1] system message からあるパターンを取り出す

open(IN,"/usr/adm/messages");
while ($line = <IN>) {
   next if $line !~ /not responding still trying/;
   $line =~ / (\d\d:\d\d:\d\d) .*sever (.*) not/;
   print "$1   $2\n";
}
close(IN);

[例 2]  先頭の2単語を swap 

s/^([^ ]+) +([^ ]+)/$2 $1/;


[例 3]  80 文字以上の行 

/.{80,}/*

[例 4]  encode and decode

encode では、英数字以外を %XX に変換する
decode では、%XX%XX を バイナリに変換する

$str =~ s/(\W)/sprintf("%%%02X",unpack("C",$1))/eg;           encode
$str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/ge;    decode

正規表現

一般的な正規表現は、ここを参照してください。 ここでは、perl に限定した事項を書きます。

正規表現のメタ文字

メタ文字 説          明
\d 数字の1文字にマッチ [0-9] と同じです
\D 数字以外の1文字にマッチ [^0-9] と同じです
\w アルファベットまたは数字(単語)の1文字にマッチ [a-zA-Z_0-9] と同じです
\W アルファベットと数字以外(単語以外)の1文字にマッチ [^a-zA-Z_0-9] と同じです
\s 空白文字にマッチ(スペース、タブ、改行) [ \n\r\f\t] と同じです
\S 空白文字以外にマッチ [^ \n\r\f\t] と同じです
(?:…) 後方参照を行わないグループ化 \1 や \2 を使用した後方参照が出来ません

ループ化と後方参照

カッコは、文字や正規表現をグループにまとめます。 また、グループにマッチした文字列は記録され、 特別な変数によって参照できます。これを後方参照といいます。 参照の仕方は、カッコで囲んだグループの左から順に、\1、 \2、\3... となります。

たとえば、Attension!のようなHTMLタグにマッチさせるには次のようになります。

m|<(.*?)>.*?|

もしタグが<b>であれば、(.*?) の部分に b がマッチし、\1 は b の値になります。 その場合は「<b>任意の文字列</b>」というパターンにマッチします。 タグが <html> であれば、「<html>任意の文字列</html>」となります。

正規表現の外部では、特殊変数を使って $1、 $2、$3... で参照できます。

$str = "Now I know His strength is within me";
$str =~ /^(\w+)/;     # 先頭の単語にマッチ

print $1, "\n";       # マッチした値を表示
>Now

マッチ変数

後方参照の変数には上記のほかに、マッチ変数 $& $` $' $+ があります。 これらの変数を使うとプログラム内のすべての正規表現の処理が遅くなるので、 注意して使ってください。

マッチ変数の一覧

メタ文字 説明
$& 文字列の中でパターン全体がマッチした部分を参照
$` 文字列の中でマッチに先行する部分を参照
$' 文字列の中でマッチに続く部分を参照
$+ 最後にマッチした文字列を返す

マッチ変数の使い方

# 最後にマッチしたワードを配列に格納
while ( /\w+/g ){ push( @words, $& ) }

選択一致パターンとグループ化の組み合わせ

選択一致パターンの | は、文字列のグループ化と組み合わせて使うと効果的です。 たとえば、Windows Me か Windows Xp という単語を探したい場合は、 次のように書くことができます。

/Windows (Me|Xp)/

ただ、グループ化すると自動的に後方参照用に記憶されるので、 多少ではありますが処理が遅くなります。 これを避けるには、後方参照を行わないグループ化の構文「(?:…)」を使います。

/Windows (?:Me|Xp)/ # マッチしたデータは記憶されない

アンカー

アンカーは、行頭や行末など、文字列中の位置にマッチします。

メタ文字 説明
^ 行頭
$ 行末
\A 文字列の先頭
\b 単語の区切り:ここで単語とは、英数字とアンダースコア( _ )です
\B 単語の区切り以外
\G 文字列の先頭、もしくは修飾子 g がついたパターンマッチングが終了した場所
\Z 文字列の最後

\A と ^ 、\Z と $ は機能がよく似ているので注意してください。 複数の行がある文字列を対象に正規表現を行った場合、 ^ は改行の直後にもマッチしますが、\A は文字列の先頭にしかマッチしません。

\Z と $ の関係も \A と ^ に似ています。 $ は改行の直前にもマッチしますが、\Z は文字列の最後にしかマッチングしません。

\b は、ワード境界とマッチします。ワード境界とは、\w と \W の間を指します。 利便性のため、文字列の先頭と末尾もワード境界とされます。

[ 例 ]

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_reg.pl
#-----------------------------------------------------
use strict;

my ($year,$month,$day);
my ($s1,$s2,$s3);
my @data1 = (
'2004-10-01','04-01-01');

my @data2 = (
'The lio_listio function allows the calling process',
'close(2),  exec(2),  exit(2),  fork(2),  lseek(2)',
'SunOS 5.7           Last change: 22 Jun 1998');


foreach (@data1)  {
   ($year, $month, $day) = /(\d+)-(\d+)-(\d+)/;
   print "\ndata is [$_]\t=======\n";
   print "$year/$month/$day\n";
}

foreach (@data2)  {
   ($s1,$s2,$s3) = ( /^(\S+)\s+(\S+)\s*(.*)/ );
   print "\ndata is [$_]\t=======\n";
   print "1=$s1 \n";
   print "2=$s2 \n";
   print "3=$s3 \n";
}

[ 実行結果 ] 
> perl t_reg.pl

data is [2004-10-01]    =======
2004/10/01

data is [04-01-01]      =======
04/01/01

data is [The lio_listio function allows the calling process]    =======
1=The
2=lio_listio
3=function allows the calling process

data is [close(2),  exec(2),  exit(2),  fork(2),  lseek(2)]     =======
1=close(2),
2=exec(2),
3=exit(2),  fork(2),  lseek(2)

data is [SunOS 5.7           Last change: 22 Jun 1998]  =======
1=SunOS
2=5.7
3=Last change: 22 Jun 1998




変数

宣言と参照

 [ 宣言 ]
局所変数は通常 my で宣言する。
複数の変数を1つの my で宣言する場合は、() で囲みます。
宣言して初期化することも可能でが、この場合は1つづつ書きます。
local で宣言しなければならないのは、特殊変数(perl でグローバルに宣言されている)
をサブルーチン内で局所的に使いたい場合などです。($_)
my と比較して local はコストが高くつきます。

 [ 例 ]
my ($hostname,$username,$password,$srcdir,$logfile);
my $ret = 1;

項目 種別 演算子 例 1例 2結果
宣言 スカラ変数 $ $scalar $scalar = 10; 10
配列 @ @array @array = ('Sun','Mon','Tue');
連想配列:ハッシュ % %ass_array %ass_array = ('smtp',25,'finger',79);
リファレンス(参照) \$ref_array $ref_array = \@array;
参照スカラ変数 $ $scalar print "$scalar \n"; 10
配列要素
配列(一部)
配列要素数-1
[ ] $array[$index]
@array[$from .. $to]
$#array
print "$array[1]\n";
print "@array[0 .. 2]\n";
print "$#array\n"
Mon
SunMonTue
2
連想配列要素 { } $ass_array{$index}
$ass_array->{$index}
print "$ass_array{"smtp"}\n";
print "$ass_array->{"smtp"}\n";
25
デリファレンス $/@/%/& @$ref_array print "@$ref_array\n"; SunMonTue

配列

一次元配列

perl は、文字列と数値を区別しませんので、 同一の配列に文字列と数値を一緒に代入できます。
また配列の添え字は、0 からはじまり、$# 配列名までです。 従って配列のサイズは、($# 配列名 +1) です。

$# 配列名に以前より大きい値を代入すると、サイズは大きくなります。 また小さい値を代入すると、サイズは小さくなります。

また undef $color[2] とすると、配列の要素数は変わりませんが、 2番目の値には未定義が格納されます。

配列の要素は [ ] で囲んで指定します。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_var.pl
#-----------------------------------------------------
use strict;

my $scalar = 10;
my @array  = ('Sun','Mon','Tue');
my %ass_array = ('smtp',25,'finger',79);
my @empsalary = ('Jone',23000,'Tiger',30000);

print $scalar  ,"\n";
print $array[1],"\n";
print @array[0 ... 2],"\n";
print @array[0,2],"\n";
print $ass_array{"smtp"},"\n";
print @empsalary[0 ... 1],"\n";
print $#empsalary,"\n";

[ 実行結果 ]
> perl t_var.pl
10
Mon
SunMonTue
SunMonTue
25
Jone23000
3 

多次元配列

多次元配列は一元配列を拡張することで、実現できます。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_array.pl
#  Function :
#-----------------------------------------------------
use strict;

my @two = ([3,7,5],[8,6,1],[4,2,9]);

$\ = " ";

print "";
print "[0,1] = $two[0][1]\n";
print "[2,2] = $two[2][2]\n";
print "[1]   = @{$two[1]}\n";
exit(0);

[ 実行結果 ]
> perl t_array.pl
 [0,1] = 7
 [2,2] = 9
 [1]   = 8 6 1 

連想配列:ハッシュ

連想配列は、文字列を添え字とする配列のことで、 通常 % 名前であらわします。
連想配列の要素は、{ } で囲んで指定します。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_assary.pl
#-----------------------------------------------------
my %assary = ('aaa',1000,'bbb',2000,'ccc',3000);
my @elem   = ('aaa','bbb','ccc');

foreach $aele (@elem) {
   print $assary{$aele},"\n";
}

[ 実行結果 ]
> perl t_assary.pl
1000
2000
3000 




リスト

配列への一括代入や関数への引数として使われる一時的配列をリストといいます。

リストは、スカラコンテキストでの評価を除けば、配列と同じ振る舞いをします。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_list.pl
#-----------------------------------------------------
my @subjects                   = ('Biology','Chemistry','Matematics');
my @empty                      = ();
my @lang;
my ($first,$second)            = (1,2);
my ($page,$edition,$version)   = ( 1, 2, 3, 4, 5);
my ($data1,$data2,@data3)      = ( 1, 2, 3, 4, 5);
my ($dat11,$dat22,@dat33)      = ( 1 .. 4);
my @card         = ('Jack','Queen','King');
my $num          = @card;
my ($first_card) = @card;

my @array = ('aaa','bbb','ccc');
my @n1    = @array;
my @n2    = ('aaa','bbb','ccc');

($subjects[3],$subjects[5]) = ('Education','History');
@subjects[0,3..5]           = ('Music','Geology','Economics','Sociology');
(@lang[1,3])                = ('Greek','Italy');

print "subjects    = @subjects   \n";
print "empty       = @empty      \n";
print "first,second= $first ,$second   \n";
print "page,edition,version = $page,$edition,$version\n";
print "data1,data2,data3    = $data1,$data2,@data3\n";
print "dat11,dat22,dat33    = $dat11,$dat22,@dat33\n";
print "lang_0,lang_1,lang_3 = $lang[0],$lang[1],$lang[3]\n";
print "subjects_0,subjects_1,subjects_2,subjects_3 = $subjects[0],$subjects[1],$subjects[2],$subjects[3]\n";
print "card       = @card\n";
print "num        = $num\n";
print "first_card = $first_card\n";
print "array      = @array\n";
print "n1         = @n1\n";
print "n2         = @n2\n";

[ 実行結果 ]
> perl t_list.pl
subjects    = Music Chemistry Matematics Geology Economics Sociology
empty       =
first,second= 1 ,2
page,edition,version = 1,2,3
data1,data2,data3    = 1,2,3 4 5
dat11,dat22,dat33    = 1,2,3 4
Use of uninitialized value at t_list.pl line 30.
lang_0,lang_1,lang_3 = ,Greek,Italy
subjects_0,subjects_1,subjects_2,subjects_3 = Music,Chemistry,Matematics,Geology
card       = Jack Queen King
num        = 3
first_card = Jack
array      = aaa bbb ccc
n1         = aaa bbb ccc
n2         = aaa bbb ccc

詳細はここを参照してください。

ハッシュ

ハッシュ変数の作成

ハッシュ変数は、配列のインデックスが文字列となったもので、 このインデックスをキーと呼びます。 ハッシュでは要素の値はキーによって管理されます。

ハッシュを宣言するときは変数名の前にパーセント( % )を付けます。 ハッシュは、 { } でキーを囲みます。 複数の値を一度にハッシュへ代入するには、キー、値の順番で記述します。 => 演算子を使うと読みやすくなります。

$hash{'Akai'}     = 'akai@domain.com';
$hash{'Ishikawa'} = 'ishi@domain.com';
$hash{'Ueda'}     = 'ueda@domain.com'; 

%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com'); 

%hash = (
  "Akai"    => "akai@domain.com",
  "ihikawa" => "ishi@domain.com",
);

ハッシュ変数の参照

%hash = ('Akai', 'akai@domain.com', 'Ishikawa', 'ishi@domain.com');

関数名 働き
keys ハッシュ変数のすべてのキーをリスト値として返します
ハッシュの要素数を調べる
@key = keys( %hash );
$n = keys( %hash );
values ハッシュ変数のすべての値をリストにして返します @value = values( %hash );
sort keys 関数が任意にリスト化したキーの順番を、文字コード順で並び替える
foreach $key ( sort keys %hash ) {
  print "key:$key\tvalue:$hash{$key}", "\n";
}
[ 実行結果 ]
 key:Akai       value:akai@domain.com
 key:Ishikawa   value:ishi@domain.com 
each ハッシュから次の要素を取り出して、キーと値のペアを返します。 すべての要素を取り出すと、未定義を返します
while ( ($key, $value) = each(%hash) ) {
    print "key:$key\tvalue:$value\n";
}
[ 実行結果 ]
 key:Ishikawa   value:ishi@domain.com
 key:Akai       value:akai@domain.com 
exists 指定したキーの値があるかを調べる
if (exists($count{$key}) ) {
    ...
} 
delete ハッシュの消去 delete $hash{'Akai'};




システム変数

特殊変数

(m) のついていない変数はグローバル変数です。 サブルーチン内で使用する場合は local 宣言することをお薦めします。

特殊変数 意味 既定値
$$ perl 自身のプロセス ID
$( perl の実グループ ID
$) perl の実効グループ ID
$< perl の実ユーザ ID
$> perl の実効ユーザ ID
$0 実行中のスクリプトファイル名
$! システムコール呼び出し時に発生したエラー番号またはエラーメッセージ
$@ eval,do,require 中で発生したエラーメッセージ
$? system,`...`,パイプを閉じたときのプロセス終了値
実際の exit 値を得るには 256 で割らなければならない

$" ダブルクオート中でリストを展開する時の要素間の区切り文字列 ' '
$# print で数値を出力する書式 %.20g
$, print 時引数間の区切り文字列 ','
$/ 入力レコード区切り文字列 '\n'
$\ 出力レコード区切り文字列 ''
$% (f) write 時の現在のページ番号
$- (f) write 時の現ページの残りの行数
$= (f) write 時参照される1ページの行数 60
$^ (f) ページ先頭の出力に使う書式の名前
$~ (f) 現書式の名前
$| (f) ファイルハンドルに対し print,write の出力をフラッシュするか
0 はフラッシュしない、非0はフラッシュする
0
$. 最後のファイル読み取り時の行番号
$; 多次元配列をエミュレートする時の区切り文字列 '\n'
$[ 配列の最初の添え字 0
$1,$2,..,$9 (m) 正規表現照合時に n 番目にマッチした内容が $n に格納される
$& (m) 直前の正規表現照合時にマッチした文字列全体
$' (m) 直前の正規表現照合時にマッチした文字列より前の部分
$' (m) 直前の正規表現照合時にマッチした文字列より後ろの部分
$+ (m) 直前の正規表現照合時 (...) にマッチした最後の内容
特に | と (...) を組み合わせた時、 どのパターンにマッチしたかを調べるときに有用

$* (m) 正規表現で複数行照会を行う場合非0にする
$_ 組み込み手続きでの省略時の引数
サブルーチンで使う場合、local 宣言しなければなりません
グローバル変数なので、前置がうわがきされてしまうからです
local $_;
foreach (@list) {
   print $_; 
}
@_ ユーザ定義関数への引数リスト
$] perl のバージョンを識別する文字列
$^D -D で指定したデバッグレベル
$^F システムファイルディスクリプタの最大数 2
$^I -i で作られるバックアップファイルの拡張子
$^L 書式出力時の改ページ文字
$^T perl 実行開始時刻
$^W -w が指定されていると1
$^X perl 自身の絶対パス

注意
(f) 出力ファイルハンドル依存な変数
(m) 直前のパターンマッチの結果を格納する局所変数


$string = "And little lambs eat ivy";
$string =~ /l[^s]*s/;
print "($`) ($&) ($')\n";

(And ) (little lambs) ( eat ivy)





定義済変数

既定義変数 意        味 使用法
@ARGV コマンド行引数
while ($arg = shift(@ARGV)) {
   print "$arg ";
} 
$#ARGV コマンド行引数の数-1 print "$#ARGV";
-1 : ないとき
DATA ファイル・ハンドル DATA はスクリプトファイル中 __END__ より後ろの部分を読み出す
while ( <DATA> ) {
   print $_;
}
__END__
data1
data2
%ENV 環境変数を保持する連想配列。キーは変数名、値は変数値 $ENV{'LANG'}
@F -a スイッチ指定時 split された文字列を格納する
@INC require,do でスクリプトファイルを検索するディレクトリ
%INC require,do でスクリプトファイルを読み込んだ時
ファイル名がキー、パス名が値として %INC に格納される

STDIN
STDOUT
STDERR
標準入出力/エラーのファイル・ハンドル $file = ; chop $file;




特殊シンボル

シンボル 機能
__END__ スクリプトの終わりを示す。
__FILE__ 現在のスクリプトファイル名
__LINE__ 現在のスクリプト中の行番号
__DATA__ DATA ハンドルが読み込むデータの開始位置




リファレンス

リファレンスは、変数、関数などのアドレスをとりだすことです。

作成

\ 演算子でリファレンスを作成できます。

my @list1=(1,2,3);
my @list2=(4,5,6);

func(\@list1,\@list2); 

デリファレンス

リファレンスをデリファレンスするには、それぞれの変数記号をつけます。 デリファレンスは、アドレスから実体をとりだすことです。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_func.pl
#  Function :
#-----------------------------------------------------
use strict;

my @list1 = (1,2,3);
my @list2 = (4,5,6);

& func_ref(\@list1,\@list2);
exit(0);


sub func_ref {
   my ($ref1,$ref2) = @_;

   print "ref1 : @$ref1\n";
   print "ref2 : @$ref2\n";
}

[ 実行結果 ] 
> perl t_func.pl
ref1 : 1 2 3
ref2 : 4 5 6 

関数のリファレンス

\ 演算子でリファレンスを、& 演算子でデリファレンスを作成できます。

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_funcref.pl
#  Function : make reference of function
#-----------------------------------------------------
use strict;

my $sub_ref = \& func;

&{$sub_ref}('one_way');
exit(0);

sub func {
   print "$_[0]\n";
}

[ 実行結果 ]
perl t_funcref.pl
one_way   




組込み関数

文字列処理操作

演算子 説明
lc(STRING) 小文字変換 $lstr = lc("AAAAA");
uc(STRING) 大文字変換 $ustr = uc("aaaaa");
chomp([STRING]) 文字列の最後の1文字を削除する chomp();
length([STRING]) 文字列長をバイト単位で返す $len = length($_);
substr(STRING,OFFSET[,LENGTH]) 文字列の OFFSET 目から LENGTH バイトの文字列を返す $sub = substr($str,3);
index(STRING,SUBSTR[,OFFSET])
rindex(STRING,SUBSTR[,OFFSET])
文字列の SUBSTR の位置を返す。ない場合は -1 $pos = index($str,"=");
sprintf(FORMAT_STRING,arg1,arg2,...) 指定された書式の文字列をかえす $str = sprintf("%4d: %s\n",lno,line);




リスト操作

演算子 説明と例
shift[(@ARRAY)]
配列 ARRAY の最初の要素を取り出し、全体に1つずれます
省略時は ARGV に対して演算を実行します
@array = ('aaa','bbb','ccc');
$first = shift(@array);
print "shift   : shift=",$first," arry=",@array,"\n";

shift : shift=aaa arry=bbbccc
unshift(@ARRAY,LIST) 配列 ARRAY の最初に要素(複数可)を追加します
$no = unshift(@array,'111','222');
print "unshift : no=",$no," arry=",@array,"\n";

unshift : no=4 arry=111222bbbccc
pop(@ARRAY) 配列 ARRAY の最後の要素を取り出します
$stack = pop(@array);
print "pop     : pop=",$stack," arry=",@array,"\n";

pop : pop=ccc arry=111222bbb
push(@ARRAY,LIST) 配列 ARRAY の最後に要素(複数可)を追加します
$no = push(@array,'ddd','eee');
print "push    : no=",$no," arry=",@array,"\n";

push : no=5 arry=111222bbbdddeee
splice(@ARRAY,OFFSET
[,LENGTH[,LIST]])
配列 ARRAY の OFFSET 番目から LENGTH 個 LIST で置換し、置換部を返します
@mem = splice(@array,3);
print "splice  : rep=",@mem," arry=",@array,"\n";

@mem = splice(@array,1,3,('AAAA','bbbb','CCCC'));
print "splice  : rep=",@mem," arry=",@array,"\n";

splice : rep=dddeee arry=111222bbb splice : rep=222bbb arry=111AAAAbbbbCCCC
sort([SUBROUTINE,] LIST) LIST の要素をソートし、結果のリストを返します
@sort = sort(@array);
print "sort    : sort=",@sort," arry=",@array,"\n";

sort : sort=111AAAACCCCbbbb arry=111AAAAbbbbCCCC
reverse(LIST) LIST の要素を逆順にし、結果のリストを返します
@reverse = reverse(@array);
print "reverse : reverse=",@reverse," arry=",@array,"\n";

reverse : reverse=CCCCbbbbAAAA111 arry=111AAAAbbbbCCCC
join(DELIM,LIST) LIST を DELIM で結合した結果のリストを返します
$join = join(':',@array);
print "join    : join=",$join," arry=",@array,"\n";

join : join=111:AAAA:bbbb:CCCC arry=111AAAAbbbbCCCC
split(/PATTERN/
[,STRING[,LIMIT]])
PATTERN に合致する文字列を区切り STRING でリストに分解します
@split = split(/:/,$join);
print "split   : split=",@split," string=",$join,"\n";

split : split=111AAAAbbbbCCCC string=111:AAAA:bbbb:CCCC
grep(EXPR,LIST) LIST の要素で EXPR(正規表現可)を満たすものを返します
@grep = grep(/[A-Z]+/,@array);
print "grep    : grep=",@grep," arry=",@array,"\n";

grep : grep=AAAACCCC arry=111AAAAbbbbCCCC




連想配列操作

演算子 説明
keys(%ARRAY) 連想配列のキーの集合を配列で返す @key_ele = keys(%ARRAY);
values(%ARRAY) 連想配列の値の集合を配列で返す @val_ele = values(%ARRAY);
each(%ARRAY) 連想配列のキーと内容を返す。なくなったら偽を返す
while (($word,$count) = each %ARRAY)  {
   print "\t$word\t$count\n";
} 
scalar(keys %ARRAY) 連想配列の指定されたキーの集合の数を返す $eleno = scalar(keys %ARRAY);
delete $ARRAY{'first'}; 連想配列の指定されたキーと値を削除する delete(%ARRAY{'first'});
exists $ARRAY{'first'}; 連想配列の指定されたキー値の存在を調べる $status = exists(%ARRAY{'first'});




ファイル、ディレクトリ操作

関数意      味
open(ファイル識別子, "ファイル名");
<  : read from
>  : write to
>& : write to  (STDOUT/STDERR)
>> : append to write to
ファイルをオープンする
open(FIN,"< aaa.out");
while (<FIN>)
   print $_;
}
close(ファイル識別子); ファイルをクローズする close(FOUT);
print ファイル識別子, "文字列"; 文字列をファイルに書く print FOUT,"$string \n";
stat (ファイル名);
ファイルの属性を知る

添え字        得られる情報
[ 0 ]    ファイルシステムのデバイス情報
[ 1 ]    |ノード番号
[ 2 ]    ファイルモード(パーミッション等)
[ 3 ]    対象ファイルのリンク数
[ 4 ]    対象ファイル所有者のユーザー ID
[ 5 ]    対象ファイルグループのグループ ID
[ 6 ]    デバイス識別子
[ 7 ]    ファイルサイズ(バイト数)
[ 8 ]    最終アクセス時間
[ 9 ]    最終変更時間
[ 10 ]   最終|ノード変更時間
[ 11 ]   最適ブロックサイズ
[ 12 ]   割り当てられているブロック数 
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks ) = stat ($filename);

システム関数

関数意      味
system(コマンド); コマンドを実行する system('ls');
exec(コマンド); コマンドを perl プログラムと置換して実行する exec('ls');

eval

eval(STRING) は、実行時に生成された STRING を perl の文として実行する関数です。
$@ は eval で実行した結果、致命的なエラーが発生した場合はエラーメッセージが、 成功した場合は空文字がセットされます。

ただし eval で指定した文字列は毎回コンパイルされるので遅くなる。

$_ = '\n';
while (<>)  {
   $a = eval($_);
   print $a       unless ($@);
}

エラー処理

関数意      味
die "メッセージ"; メッセージとともに実行を終わる die "Cannot open data file.\n";
warn "メッセージ"; メッセージを出す warn "Invalid data\n";




文字と文字列

プレフィックス

文字意      味
@配列変数 @array
%連想配列変数:ハッシュ変数 %array
$スカラ変数(普通の変数) $num
\変数のリファレンスをとる(アドレス) $addr = \@aaa;

引用符

引用符意      味
' この引用符で囲まれた文字列中のメタ文字は無視します $var1 = '$ARGS'; # $ARGS そのもの
" この引用符で囲まれた文字列中の $ ` \ 以外のメタ文字は無視します $var1 = "$ARGS"; # $ARGS の値
qr() 括弧内の文字列は quoted regular expression として扱える $var1 =~ qr([a-zA-Z0-9]+); # 英数にマッチするもの
qq() 括弧内の文字列は quoted string として扱える @var1 = qq(It's a beautiful world);
qw() 括弧内の文字列は quoted word として扱える qw| .......|
qw\ .......\

メタ文字

メタ文字 説明
\n 改行(UNIXではLF)
\r キャリッジリターン(UNIXではCR)
\t タブ
\f 改ページ文字
\b バックスペース
\a アラート/ベル
\e エスケープ文字(ESC)
\0数字 8進数でビットの並びを指定(したその文字)
\x数字 16進数で指定
\cC コントロールC
\x{数字} UNICODEの文字
\u 次の1文字を大文字に変換
\l 次の1文字を小文字に変換
\U これ以降の全ての文字を大文字に変換
\L これ以降の全ての文字を小文字に変換
\Q これ以降の、全ての半角英数字以外の前に逆スラッシュを挿入
\E \U \L \Q の効果をここで打ち消す




入出力

ファイル・ハンドル

ファイルハンドルは、 perl プログラムが他のファイルを参照するときに使う名前のことで、 独自の名前空間にて管理されている。 通常大文字で記述します。 perl では STDIN、STDOUT、STDERR をあらかじめオープンしています。 標準装備以外のファイルハンドルを使う場合、 open 関数を使ってオープンする必要があります。

  1. STDIN
  2. STDOUT
  3. STDERR
  4. <> コマンド行で指定したファイル

open(IN,"ファイル")    || die("Open error");    [read]
open(OUT,">ファイル")  || die("Open error");    [write]
open(APP,">>ファイル") || die("Open error");    [append]
if (! open(APP,">>ファイル"))   { exit(1);}     [append]
open ( filehandle, "command |" );               コマンドの出力を読み込む 
open ( filehandle, "| command" );               出力をコマンドに送る 

while(<IN>) {
   chomp;
   print $_;
}




入出力切り替え

ファイルハンドルには、いろいろな使い方があります。

  1. ファイルがパイプの場合 (t_sort.pl)

    このプログラムは、カレントディレクトリの ls の結果をソートして印刷します。

    #!/usr/local/bin/perl -w
    #-----------------------------------------------------
    #  FileName : t_sort.pl
    #-----------------------------------------------------
    open(SORTED,"ls|sort|uniq|") || die "ERROR: sort command\n";
    while ()   {
       chomp();
       print "$_ ";
    }
    close(SORTED);
    

  2. ファイルが実行可能である場合 (t_cmd.pl)

    #!/usr/local/bin/perl -w
    #-----------------------------------------------------
    #  FileName : t_cmd.pl
    #  Usage    : perl t_cmd.pl lc
    #-----------------------------------------------------
    use strict;
    
    my %command;
    my $cmdname;
    my @answer;
    
    $cmdname = $ARGV[0];
    %command = (
     'netstat_a' => 'netstat -a',
     'lc'        => 'ls -aCF',
     'pse'       => 'ps -ef ',
    );
    if (!(open (CMD,"$command{$cmdname} 2>&1 |")))  {
      print ("error\n");
    }
    
    @answer = ;
    print @answer;
    close(CMD);
    
    [ 実行結果 ]
    ozzy-4 07/07 11:26am] perl t_cmd.pl lc
    ./                 prep*              t_ary.pl           t_sub.pl
    ../                ps.pl              t_assary.pl        t_time.pl
    ABC/               save.cgi           t_cmd.pl           t_tstdata.pl
    LOCK               search.cgi         t_comma.pl         t_var.pl
    RESULT             sep.pl             t_data.pl          t_while.pl
    bb                 sep.pl.old         t_for.pl           tbl.pl
    book/              sep_tcp.pl         t_foreach.pl       text/
    

ヒアドキュメント

プログラムの中に直接ドキュメントを書く方法をヒアドキュメントといいます。 もちろんその中に変数名があると、値に置き換わります。

print <<_END_OF_DOC       ここから _END_OF_DOC までがドキュメントです
data1
data2
$addr                          $addr の値が印刷されます 
_END_OF_DOC               必ず行頭でなければなりません




モジュール

モジュール名の1文字目は大文字が慣例です。

スケルトン

h2xs -Xn モジュール名
pl2pm perl プログラム名

これで新規のディレクトリ(モジュール名)以下にスケルトンが作られます。
実際のモジュール名は、モジュール名.pm です。

作成

package 文は、名前空間を宣言します。 従って以降の名前空間は main ではなく、package で指定した名前となります。

package  cgi_util;        <== モジュール名でファイルをつくる(cgi_util.pm) 
@EXPORT = qw(file_mode);  <== 外部参照できるようにする

#------------------------------------------------
# Function : pickup 1st char of directory info
# Return   : mode
# mode   d: dir
#        -: file
#        l: symbolic link
#------------------------------------------------
sub file_mode {
   local ($lmode)=$_[0];
   local ($first);

   $first = substr($lmode,0,1);
   $first;
}

1;                         <== use で読めるようにする 

参照

use cgi_util;                     <== include する 

$lmode = file_mode($dir_info); <== call 

FTP

perl で FTP を行うには、FTP.pm モジュールを使うと簡単に実現できます。

use Net::FTP;     # FTP                          include FTP モジュール

my ($ftp,$status,@list);
my ($hostName,$userName,$passWord,$srcDir,$base_dir,$dir_base);
my $PRG_NAME = 'unix_load.pl';

# connect
$ftp = Net::FTP->new($hostName, Debug => 0);                    connect
&err_msg('ERROR : connect',$hostName,$PRG_NAME)      unless ($ftp);
$status = $ftp->login($userName, $passWord);                    logon
&err_msg('ERROR : logon ',$userName,$PRG_NAME)       if ($status == 0);

# chdir to HOME
$status = $ftp->cwd($srcDir);                                   cwd
&err_msg('ERROR : non exists ',$srcDir,$PRG_NAME)        if ($status == 0);

# get dir informations from remote host
$base_dir = $ftp->pwd();                                        pwd
@list = $ftp->ls("-l $dir_base");                               ls -l

# disconnect
$ftp->quit;                                      disconnect




オブジェクト指向

クラスの作成

クラスの宣言

クラスはパッケージですから、package 文を使ってクラスを宣言します。

package クラス名;
コンストラクタの作成

コンストラクタは、新しいオブジェクトを作成しそのリファレンスを返すメソッドです。 クラス作成の順番は次のようになります。

  1. new という名前でメソッドを定義する
  2. 第1引数のクラス名を受け取る
  3. bless 関数でオブジェクトのリファレンスを返す
コンストラクタは new という名前で宣言します。 第1引数としてクラス名が渡される決まりなので、それを受け取ります。

package Class;

sub new {
    my $class = shift;
    ....
}

オブジェクトを用意します。 ここでは、無名ハッシュのリファレンスを作成していますが、ハッシュ以外にもスカラや配列を返しても問題ありません。

# 無名ハッシュのリファレンスを作成
my $self = {};

 ここでオブジェクト属性をセットしておくこともできます。

my $self = { x=10, y=20 };

 あとは bless 関数に作成したオブジェクトとクラス名を渡して終わりです。

# bless したオブジェクトリファレンスを返す
return bless $self, $class;

bless 関数とは?

bless 関数の引数は、リファレンスとパッケージ名です。 第1引数で与えられたリファレンスが指すオブジェクトは、 第2引数で指定したクラスに所属します。 第2引数のパッケージ名はオプションを省略すると現在のパッケージ名を引数とします。

my $self = {};
bless $self, $class;

bless した変数はクラスのオブジェクトに属することになるので、 普通の変数と区別するためにインスタンスと呼ばれます。 ここでは単純に、「bless の第1引数としてw定した変数がインスタンス」とおぼえておいてください。

コンストラクタとデストラクタ

package Class;
# コンストラクタ定義
sub new {
    my $class= shift;
    bless { x => shift }, $class;
}

# デストラクタ定義
sub DESTROY{
    my $self = shift;
    print "DESTROY > $self->{x}", "\n";
}
#------------------------------------------#
package main;

$a = new Class( '001' );
{
    my $b = new Class( '002' );
}
# $b がスコープ外となり、'002' のオブジェクトが破棄される

# '001' は上書きされ、そのオブジェクトが破棄される
$a = new Class( '003' );

 出力結果は次のようになります。

DESTROY > 002    # スコープの外に出た瞬間にDESTROYが呼ばれる
DESTROY > 001    # 上書きされた瞬間にDESTROYが呼ばれる
DESTROY > 003   # スクリプト終了直前にDESTROYが呼ばれる

クラスの継承

オブジェクト指向の「継承」を使えば、元のクラスの資源をもとに、 新しいクラスを簡単に作成することができます。 オブジェクト指向では、元になるクラスをスーパークラス、 それから派生したクラスをサブクラスと呼びます。

@ISAを使っ て継承する

既存のクラスを継承してサブクラスを定義するには、 サブクラス内で @ISA にスーパークラスの名前をセットします。

ClassA.pm という名前でスーパークラスを作成しましょう。

# ClassA を宣言(ClassB のスーパークラスになります)
package ClassA;

# コンストラクタの作成
sub new {
    my $class = shift;
    my $self = { x => 10 };
    bless $self,$class;
}
# メソッドの作成
sub print_x{
    my $self = shift;
    print $self->{x}, "\n";
}
1

次に、 ClassB.pm という名前でサブクラスを作成します。

# ClassB を宣言
package ClassB ;

# パッケージAの使用を宣言
use ClassA;

# @ISAにスーパークラスの名前「A」を設定
# これによってクラスBはクラスAを継承する
@ISA = qw ( ClassA ); 

# ClassB のコンストラクタ
sub new {
    my $class = shift;

    # ClassA のコンストラクタを呼び出す
    my $self = new ClassA;
    return bless $self;
}
1

これだけで継承が終わりました。 上記のクラスB は、クラスA のメソッドを全て受け継いでいます。

それでは、ClassB のコンストラクタに注目してください。 クラスに属したオブジェクトの作成で、ClassA のコンストラクタを呼び出しています。 ClassA から返されたオブジェクトリファレンスをそのまま ClassB のインスタンス変数として bless しています。 これで、ClassA のメソッド、インスタンス変数がすべてアクセス可能になりました。

ClassB を呼び出し、ClassA の print_x メソッドを利用するには次のようになります。

use ClassB;

my $obj = new ClassB;

# メソッドの読み出し
$obj->print_x;

呼び出し側では、print_x メソッドが ClassA と ClassB のどちらかで定義されているかを気にする必要はありません。ただ呼び出すだけです。

スーパークラスのメソッドをオーバーロードする

スーパークラスのメソッドと同名のメソッドを定義することを、 「オーバーロード」と呼びます。 変数に新しい値を代入するのと同じように、スーパークラスのメソッドを上書きできます。

以下の例は、スーパークラスのメソッドをオーバライドし、 オーバライドされた後でそのメソッドを呼び出しています。

#--------------------------------------#
# スーパークラスを定義
package Unix;

sub print_x { print "UNIX! \n" }

#--------------------------------------#
# サブクラスを定義
package Linux; 

@ISA = qw( Unix );
sub new { bless {} }
sub print_x { print "LINUX! \n" }

#--------------------------------------#
package main;
my $obj = new Linux;
$obj->print_x;

オーバーロードした元のメソッドを使う

サブクラスでオーバーロードされた元のメソッドは、 スーパークラスを表す SUPER という擬似クラスで呼び出せます。

# スーパークラスの new メソッド呼び出し
my $obj = $class->SUPER::new( $x, $y );

これでスーパークラスのコンストラクタ new メソッドが実行されます。 スーパークラスのメソッドを呼び出すには、クラス名::メソッド名とします。 モジュールからサブルーチンを参照する方法と同じ記法ですね。

多重継承

配列@ISAには複数のクラス名を設定することが出来ます。 この場合、2個以上のクラスからメソッドを継承することになります。 これを多重継承といいます。

多重継承の場合、@ISAに設定されたスーパークラスを1つづつ順に並べて、 起動すべきメソッドを探します。

#--------------------------------------#
# スーパークラスを定義
package Unix;

sub unix { print "UNIX! \n" }

#--------------------------------------#
# サブクラスを定義
package Linux; 

@ISA = qw( Unix );
sub linux { print "Linux! \n" }

#--------------------------------------#
package Mac;
sub mac { print "mac! \n" }

#--------------------------------------#
package Foo;

@ISA = qw( Google Infoseek );
@Foo::Inherit::ISA = @ISA; # オーバライドされたメソッドのアクセス

sub new { bless [] }
sub goo {
    my $self = shift;
    $self->Foo::Inherit::goo();
}
sub google {
    my $self = shift;
    $self->Foo::Inherit::google();
}
sub infoseek {
    my $self = shift;
    $self->Foo::Inherit::goo();
}
sub grr { print "grumble\n" }
#--------------------------------------#

package main;

$foo = new Foo;
$foo->goo;
$foo->google;
$foo->grr;




環境

オプション

オプション 機          能
-n whicle(<>) { } 内で実行
-p 各ループの最後に print; を実行する。通常 -n と併用する
-w 識別子について様々な警告を出す。
-c スクリプトの文法をチェックし、実行せずに終了する。
-d perl デバッガのもとでスクリプトを実行する。
-P C プリプロセッサを通す。つまり、#include や #define が使える。
-I require のファイルまたは -P の include の検索するディレクトリを指定
-v バージョン表示





perl 4 VS 5

項目 説          明
局所変数 これまでの local に加えて、 my ができました。
eval これまでは eval の引数は文字列で、 プログラムを実行時に作る目的で使われましたが、 これに加えて、引数にブロックを取るものができました。 これは、例外処理に役立ちます。
サブルーチン呼び出し 呼び出すところより前で宣言されているサブルーチンを呼び出す時は、 サブルーチン名の前に & をつけなくてよくなりました。 これにより、ユーザが定義した関数や、ライブラリの関数も、 組み込み関数としなくてよくなりました。
サブルーチンの引数の型宣言 引数の型を宣言することで、ミスがチェックできるようになりました。 また、コンテキストを特定することもできるようになりました。
BEGIN, END コンパイル時に実行する BEGIN と、 終了時に実行する END という 特別なサブルーチンが用意されました。 これは、 -n スイッチなどを使った一行プログラムで、 AWK の BEGIN, END と同じ役割をするので特に便利です。
参照 参照ができました。 C でいうところの、「ポインタ」のようなものです。 これを使って、多次元配列を始めとする 複雑なデータ構造が作りやすくなりました。
モジュール ライブラリはモジュール化されました。 さまざまなモジュールが用意されています。
オブジェクト指向 モジュールを使って、オブジェクト指向プログラミングが実現されました。
正規表現の拡張 正規表現中にコメントが書けるようになりました。
表記法 連想配列のキーと値の対応を示す => や、 文字列のリストを表現する qw など、新たな表記法が加わりました。
組み込み関数の改良 chop の改良版である chomp など、新たに組み込み関数が追加されたり、 機能が変更されたりしています。




その他

  1. 日時を得る
  2. HTML の <hX> ... </hX> を取り出す
  3. コマンドの実行

日時を得る

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_time.pl
#-----------------------------------------------------
use strict;
use POSIX;

my $date;

$date = & mk_date();
print "$date\n";
exit(0);

#------------------------------------------------
# Function : make current date string
# Return   : date string
#------------------------------------------------
sub mk_date {
   my ($time_t,$mday,$hour,$min,$sec,$mon,$year,$wday,$yday,$isdst,$buf) ;

   $time_t = time();
   ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time_t);
   $year   += 1900;
   $mon    += 1;
   $buf = sprintf("%4d/%02d/%02d %02d:%02d:%02d",
                  $year,$mon,$mday,$hour,$min,$sec);
   return $buf;
}

[ 実行結果 ]
2004/07/07 13:51:37

HTML の <hX> ... </hX> を取り出す

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : pk_html_h.pl
#  Function : convert <h1> to <H1>
#-----------------------------------------------------
use strict;

my $lno=0;

while (<>)  {
   $lno ++;
   chomp($_);
   if (m|(<h[1-6]>)|)  {
      s|||g;
      s|||g;
      print "$lno]  $_  \n";
   }
}
exit(0);

[ 実行結果 ]
> cat namazu.html | perl pk_html_h.pl
8]  <H1> namazu </H1>
451]  <H5>必要条件 </H5>
468]  <H5>起動と停止 </H5>
483]  <H5>必要条件 </H5>
500]  <H5>起動と停止 </H5>
509]  <H5>必要条件 </H5>
525]  <H5>起動と停止 </H5>

コマンドの実行

#!/usr/local/bin/perl -w
#-----------------------------------------------------
#  FileName : t_cmd.pl
#  Usage    : perl t_cmd.pl lc
#-----------------------------------------------------
use strict;

my %command;
my $cmdname;
my @answer;

$cmdname = $ARGV[0];
%command = (
 'netstat_a' => 'netstat -a',
 'lc'        => 'ls -aCF',
 'pse'       => 'ps -ef ',
);
if (!(open (CMD,"$command{$cmdname} 2>&1 |")))  {
  print ("error\n");
}

@answer = ;
print @answer;
close(CMD);
exit(0);

[ 実行結果 ]
> perl t_cmd.pl lc
./                 prep*              t_ary.pl           t_sort2.pl
../                ps.pl              t_assary.pl        t_sub.pl
ABC/               save.cgi           t_cmd.pl           t_time.pl
LOCK               search.cgi         t_comma.pl         t_tstdata.pl
RESULT             sep.pl             t_data.pl          t_var.pl

デバッグ

  1. コンパイラでのチェック

    #!/usr/local/bin/perl -w オプション
    use strict;
    use diagnostics;
    use constant  DEBUG => 1;
    

  2. Dumper で表示

    use Data::Dumper;
    print Dumper \%list;
    

  3. デバッガを使う (perl -d XXX.pl)

デバッガのコマンドは以下のとおりです。

機能 コマンド 内容
ブレイク T スタック・トレースを行います
L ブレイク・ポイントまたはアクションを持つ行を表示します
S すべてのサブルーチン名をリスト表示します
t
トレース・モードを切り替えます。
このコマンドは、トグルになっており、現在 on なら off に、
現在 off なら on に切り替えます
b line [condition]
ブレイク・ポイントを設定します。
line を省略すると、現在行のブレイク・ポイントを設定します。
condition を指定すると、condition が真のとき実行を中断します。

記述例 : b 23 $x > 30
b subname [condition] サブルーチンの最初の実行文に、ブレイク・ポイントを設定します
d line
指定した行のブレイク・ポイントを削除します。
line を省略すると、現在行のブレイク・ポイントを削除します
D すべてのブレイク・ポイントを削除します
実行 s シングル・ステップ。別の実行文に到達するまで実行します
n 次の実行文までを、サブルーチンを含めて実行します
f 現在のサブルーチンを終えるところまで実行します
c
c line
次のブレーク・ポイントまで実行します。
指定した行までを実行します
<CR> 最後に実行した n コマンドまたは s コマンドをリピートします
! number デバッグ・コマンドを再実行します。
number を省略すると、直前のコマンドを実行します
! -number number で指定した数だけ前のコマンドを実行します
q or ^D デバッガを終了します
command
>指定した command を、Perl の文として実行します。
文末のセミコロンは省略できます

p expr print DB::OUT expr と同じです
値表示 p $symbols 指定した変数を表示します。
V package [symbols] 指定したパッケージ内のすべての変数を表示します。
symbol は $ などを付けず、名前だけを指定します。
X [symbols] 現在のパッケージ内のすべての変数を表示します。
symbol は $ などを付けず、名前だけを指定します。
リスト l 次の1画面をリスト表示します
l min+incr
min 行から incr+1 行をリスト表示します。min を省略すると、
最後にリスト表示を実行した最後の行から表示します。
incr を省略すると、前回実行したときの incr が使われます 
l min-max 指定した範囲をリスト表示します。
l line 指定した行をリスト表示します
l subname
指定したサブルーチンをリスト表示します。
長いサブルーチンの場合は、最初の1画面分を表示します。
続きは l コマンドで表示されます。 
- 前の1画面をリスト表示します
w line 指定した行の付近をリスト表示します
H -number
最近実行したコマンドで、number で指定した数のコマンドを表示します。
2文字以上のコマンドだけが表示されます。
number を省略すると、すべてを表示します。
検索 /pattern/ ソース・コード上で、正規表現 pattarn を検索します。
最後の / は省略できます
?pattern? ソース・コード上で、正規表現 pattarn を逆方向に検索します。
最後の ? は省略できます。
コマンド a line command
指定した行にアクションを設定します。
複数行の command を指定する場合は、バックスラッシュと改行を使います。
command はデバッガのコマンドではなく、Perl のコマンドを指定します
< command
デバッガがプロンプトを表示する前に実行するアクションを指定します。
このアクションは、毎回実行されます。
複数行の comannd を指定する場合は、バックスラッシュと改行を使います
> command
プログラムの実行に戻るコマンドを入力したとき、
デバッガがプロンプトを表示した後に実行するアクションを指定します。
このアクションは、毎回実行されます。
複数行の command を指定する場合は、バックスラッシュと改行を使います。
A すべてのアクションを削除します
h ヘルプ・メッセージを表示します。

エラー対処法

予約語

AUTOLOAD
BEGIN
CHECK
CORE
DATA
DESTORY
END
GLOBAL
INIT
EQ,GE,GT,LE,LT,NE
STDIN,STDOUT,STDERR

ツール

perldoc perl
man perldebug

FAQ

  1. 再帰呼び出しするサブルーチンで $_ がうまく機能しないのはなぜ?
  2. foreach $i (1..10) の実行後 $i の値がおかしいのはなぜ?
  3. 文字列に " や ' を含む場合はどうすればいいでしょうか?
  4. local と my の違いはなんでしょうか?
  5. packge と module の違いはなんでしょうか?
  6. サブルーチンに配列変数を渡したいのですが?

  1. 再帰呼び出しするサブルーチンで $_ がうまく機能しないのはなぜ?
    $_ はグローバル変数なので、再帰呼び出しされるサブルーチンでは必ず
    local 宣言しないと、値が変えられてしまう可能性があります。
    local 宣言すると、宣言したところで、局所的な変数扱いとなりますが、
    そこを出ると、以前の値がセットされます。
    
    local $_;
    
  2. foreach $i (1..10) の実行後 $i の値がおかしいのはなぜ?

    $i の実行後の値は初期値に再設定され、10 ではありません。

  3. 文字列に " や ' を含む場合はどうすればいいでしょうか?

    print qq(string "string" 'string' string);

  4. local と my の違いはなんでしょうか?
    my:
      宣言スコープ内側に完全にプライベート。
      これをレキシカルスコープという。
        静的スコープ
        perl 5 から導入された
    local:
      宣言スコープ内から呼ばれる他の別空間スコープ(関数内)からもアクセス可。
        動的スコープ
        システム予約変数を局所的に使いたい時使用する。
        local は局所変数ではなく、単に宣言したスコープでは別の値を持つように
        しているだけです。
    
    #!/usr/local/bin/perl -w
    #-----------------------------------------------------
    #  FileName : t_my_local.pl
    #  Function : test of my and local
    #-----------------------------------------------------
    $a = "global"; test();
    {
       local $a="local"; test();
    }
    {
       my $a="my";test();
    }
    exit(0);
    
    sub test {
       print "a=$a \n";
    }
    
    [ 実行結果 ]
    > perl t_my_local.pl
    a=global
    a=local
    a=global
    

  5. サブルーチンに配列変数を渡したいのですが?

    配列のリファレンス(アドレス)を渡すことで、実現できます。

    my (@ary1,@ary2);
    
    &sub1(\@ary1,\@ary2);             配列のリファレンスを渡す
    
    sub sub1 {
       my ($parm1,$parm2) = @_ ;      リファレンスを変数に設定する
       print "@$parm1\n";             リファレンスから実体を参照する
       print "@$parm2\n";             リファレンスから実体を参照する
    }
    

略語集

略語 説明
CGI Common Gateway Inteface
CPAN Comprehensive Perl Archive Network
POD Plain Old Document
SSI Server Side Include

参考書

名前 出版社 値段
新 perl の国へようこそ サイエンス社 3200
プログラミング perl マスターコース ピアソンエデュケーション 3400
perl デバッグ ピアソンエデュケーション 2600
perl & CGI ピアソンエデュケーション 4600
CGI プログラミング オーム社 2600
CGI 基礎講座 翔詠社 2800

リンク集

perl マニュアル ワンライナー perl CGI 入門 プログラミング講座
perl 情報 perl バイブル

モジュール マニュアル FreePerl.com Jcode.pl
ユーザグループ 東京 CGI 関連

用語集

用語 意味
キャプチャ 正規表現でマッチしたものを特殊変数 $1,$2,... に格納すること
クロージャ 無名サブルーチンへのリファレンス
リスト スカラーデータに順序を付けて並べたもの
スライス 同一の配列に含まれる複数の要素にアクセスすること




CGI

CGI

  1. CGI で perl を使う場合は、1行目が以下でなければなりません。 また実行許可がなければなりません。

    #!/usr/local/bin/perl
    

  2. <FORM ACTION=XXX.pl?arg1+arg2 METHOD=POST>
    引数は %ENV{'QUERY_STRING'} に格納されます。
    引数が日本語の場合、%ENV{'HTTP_ACCEPT_CHARSET'} で示されるコードになっています。
    例えば、UNIX マシンで実行する perl を Windows 上に表示している場合、
    SJIS に変換されていますので Jcode を使って EUC に変換します。
    
    $cur_dir   = Jcode::convert($query,'euc');
    

    ただしブラウザにより動作が異なります。 IE の場合、日本語の変換が正しく行われない。 (回避策としては、encode する)

  3. <FORM ACTION=XXX.pl METHOD=POST>
    <INPUT TYPE="checkbox"  NAME="box" VALUE="UNIX" CHECKED >UNIX
    <INPUT TYPE="checkbox"  NAME="box" VALUE="DOS" >DOS
    <INPUT TYPE="checkbox"  NAME="box" VALUE="WiNNT" >WinNT
    <INPUT TYPE="checkbox"  NAME="box" VALUE="LINUX" >LINUX
    <INPUT TYPE="submit" VALUE="実行"> 押してください
    </FORM>
    
    POST されたデータ長は %ENV{'CONTENT_LENGTH'} に格納されます。 これを STDIN から読み込みます。

    ただし、この文字列はエンコードされていますので、 デコードする必要があります。

    read(STDIN,$qstr,$ENV{'CONTENT_LENGTH'});
    ($title,$linkname) = split(/=/,$qstr);
    $linkname          =~ s/%([a-fA-F0-9][[a-fA-F0-9])/pack("c",hex($1))/ge ;
    

    https の場合、REQUEST_METHOD の POST が GET になってしまい、 %ENV{'QUERY_STRING'} に格納されてしまうことがあります。

環境変数

CGI の場合、環境変数は %ENV で perl プログラムに渡されます。 環境変数とその値を列挙すると、概ね以下のとおりです。

ブラウザ情報は HTTP_USER_AGENT = Mozilla/4.75 [ja] (Windows NT 5.0; U) にあります。

SERVER_SOFTWARE = Apache/1.3.6 (Unix)
GATEWAY_INTERFACE = CGI/1.1
DOCUMENT_ROOT = /home06/websrv
REMOTE_ADDR = 172.30.33.68
SERVER_PROTOCOL = HTTP/1.0
SERVER_SIGNATURE = 
Apache/1.3.6 Server at ozzy.open.enicom.co.jp Port 8080

REQUEST_METHOD = POST
HTTP_REFERER = http://bach.it.ns-sol.co.jp:8080/hp/taka/HP/html_CGI.html
QUERY_STRING = 日本語+システム
HTTP_USER_AGENT = Mozilla/4.75 [ja] (Windows NT 5.0; U)
PATH = /usr/sbin:/usr/bin:/usr/ccs/bin:/usr/proc/bin:/usr/local/bin:/usr/local/sbin
TZ = Japan
HTTP_ACCEPT = image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
REMOTE_PORT = 30728
HTTP_ACCEPT_LANGUAGE = ja
HTTP_CACHE_CONTROL = max-stale=0
SCRIPT_NAME = /cgi-bin/tst.pl
HTTP_ACCEPT_ENCODING = gzip
SCRIPT_FILENAME = /home06/taka/cgi-bin/tst.pl
SERVER_NAME = ozzy.open.enicom.co.jp
REQUEST_URI = /cgi-bin/tst.pl?日本語+システム
HTTP_ACCEPT_CHARSET = Shift_JIS,*,utf-8
SERVER_PORT = 8080
CONTENT_TYPE = multipart/form-data; boundary=---------------------------26972134376704
CONTENT_LENGTH = 47
HTTP_HOST = ozzy.it.ns-sol.co.jp:8080
SERVER_ADMIN = websrv@ozzy.open.enicom.co.jp

ブラウザ情報

ブラウザ HTTP_USER_AGENT/HTTP_ACCEPT_CHARSET
Netscape 4.7
Mozilla/4.75 [ja] (Windows NT 5.0; U)
Shift_JIS,*,utf-8 
MSIE 6.0
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) 
Mozilla 5.0
Mozilla/5.0 (Windows; U; Windows NT 5.0; ja-JP; rv:1.7.1) Gecko/20040707
Shift_JIS,utf-8;q=0.7,*;q=0.7
Opera 7.23
Mozilla/5.0 (Windows NT 5.0; U) Opera 7.23  [ja]
shift_jis, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1

内包される Mozilla のバージョンにより、日本語処理が異なり、 5.0 ja-JP であると、内部コードは EUC となります。




マニュアル

online マニュアル

 
perldoc -f サブルーチン名      perl のサブルーチンの man を知る
perldoc モジュール名           perl のモジュールの man を知る

perldoc POSIX                  POSIX モジュールの説明
perldoc CGI                    CGI   モジュールの説明
perldoc constant               定義済み定数の説明