とほほのperl入門(概要編)

トップ > とほほのperl入門 > 概要編

Perlとは

インストール

# RHEL7系
# yum -y install perl

# RHEL8/9系
# dnf -y install perl

# Ubuntu系
$ sudo apt -y install perl

実行方法

引数指定

コマンドプロンプトから次のように入力してください。-e オプションは次に続く '...' を Perl スクリプトとして実行します。

perl -e 'print "Hello world!\n"'
ファイル指定

次のような内容のテキストファイル(仮にhello.plとします)を作成してください。

print "Hello world!\n";

上記で作成したファイルの名前を引数にして、コマンドプロンプトから次のようにperlコマンドを実行してください。

perl hello.pl
自己完結型

Linux系OSで使用可能な方法です。次のような内容のテキストファイル(仮にhello.plとします)を作成してください。

#!/usr/bin/env perl
print "Hello world!\n";

env を使用すると環境変数 PATH の中から perl コマンドを探してくれます。perl コマンドのパスが明確であれば下記の様に記述しても構いません。

#!/usr/bin/perl
print "Hello world!\n";

#! というのは Linux系特有の機能で、その後ろに続くコマンドを起動するためのおまじないです。chmodコマンドを次のように使用してファイルのモードを変更してください。

chmod 755 hello.pl

コマンドプロンプトから次のように入力して実行してください。

./hello.pl
Hello world!
標準入力読み込み型

perlコマンドの引数が指定されていない場合、標準入力から読み取った内容をperlスクリプトとして実行します。

echo 'print "Hello World!\n";' | perl

基礎知識

簡単な実行例

次の例では変数 $x に 5 を、変数 $y に 2 を代入し、その合計を変数 $z に代入した後、結果を表示します。

$x = 5;
$y = 2;
$z = $x + $y;
print "$z\n";      # => 7
これだけは覚えて

以後の説明を楽にするために、上記の実行例についてこれだけは覚えておいてください。

strictモードと警告モード

プログラムの先頭に下記の2行を記述することが推奨されています。strict は Perl の文法を厳密にチェックします。warnings は詳細な警告メッセージを出力します。プログラムのミスを早期に見つけるのに効果的です。

use strict;
use warnings;

strictモードの場合、上記のプログラムは下記の様に変数宣言 my をつける必要があります。

my $x = 5;
my $y = 2;
my $z = $x + $y;
print "$z\n";      # => 7
関数の括弧

print などの関数に引数を渡す場合、次のように括弧無しで渡すことができます。

print "...";

また、C言語などのように括弧付きで記述することもできます。

print("...");

定数

数値

次のような表現の数値を使用することができます。

12345          # 整数
12_345         # 整数(アンダーバーは無視されます。桁区切りに使用可能)
1.23           # 小数
1.23E45        # 浮動小数点数(E)
1.23e45        # 浮動小数点数(e)
0x12345        # 16進数(0x)
012345         # 8進数(0)
0o12345        # 8進数(0o)
0b10011        # 2進数(0b)
文字列

文字列はダブルクォーテーション( " )またはシングルクォーテーション( ' )で囲みます。

"abc"
'abc'

ダブルクォーテーションの中ではシングルクォーテーションを、シングルクォーテーションの中ではダブルクォーテーションを使用することができます。

"abc'def'ghi"
'abc"def"ghi'

どうしてもダブルクォーテーション中にダブルクォーテーションを使用したい時は、バックスラッシュ( \ )を用います。

"ダブルクォーテーション(\")を使う"

ダブルクォーテーションの中では変数やバックスラッシュ( \ )が評価されますが、シングルクォーテーションの中では単なる文字として認識されます。

my $xx = 7;
print "Answer is $xx.\n";     # => Answer is 7.
print 'Answer is $xx.\n';     # => Answer is $xx.\n
エスケープシーケンス(\)

ダブルクォーテーションで囲まれた文字列の中ではバックスラッシュ( \ )に続く文字は特別な意味を持ちます。

\t        # タブ文字(\x09)
\n        # 改行(\x0a)
\r        # リターン(\x0d)
\f        # フォームフィード(\x0c)
\b        # バックスペース(\x08)
\a        # アラーム(\x07)
\e        # エスケープ文字(\x1b)
\033      # 文字コード(8進数)
\x1b      # 文字コード(16進数)
\c[       # コントロール文字
\l        # 次の1文字を小文字にする
\u        # 次の1文字を大文字にする
\L        # \Eまでの文字列を小文字にする
\U        # \Eまでの文字列を大文字にする
\E        # \Lや\Uを終了させます
\" など   # ダブルクォーテーション( " )自身を表わします。
数値と文字列

perlでは、数値と文字列の扱いはあいまいで、その都度数値として評価されたり、文字列として評価されたりします。次の例では1行目では文字列の 12345 が代入されていますが、2行目では加算演算子により臨機応変に数値として解釈され、12350 が表示されます。

my $xx = "12345";
print $xx + 5;
真(true)と偽(false)

if ( ) 文の中などの真偽判断では、空文字列("")、ゼロ(0)、ゼロを示す文字列("0")、未定義値は偽として、それ以外は真として扱われます。true や false という特殊な変数がある訳ではないので、return(false) は、"false" という文字列を返却することになります。真偽を返却する関数を評価する際は if (&func() == true) ではなく、if (&func()) と評価してください。

バイナリデータ

バイナリデータを扱うことができます。pack と unpack はバイナリデータに対して、文字表現、数値表現の変換を行います。次の例を実行すると [ABC] [65 66 67] [ABC] と表示されます。

my $xx = "ABC";                      # 文字列としての代入
my @yy = unpack("C*", $xx);          # 数値の配列に変換
my $zz = pack("C*", @yy);            # 数値の配列を文字列に変換
print "[$xx] [@yy] [$zz]\n";         # => [ABC] [65 66 67] [ABC]

変数

変数宣言(my)

変数の使用を始めるには my を用いて変数を宣言します。my を省略することもできますが、strictモード の場合は必須となります。

my $xx1;
my $xx2 = 123;
my $xx3 = "ABC";
my @xx4 = (1, 2, 3);
my %xx5 = (name => "Yamada", age => 26);
スカラ($XXX)

ダラー($)で始まる変数はスカラー変数と呼ばれます。スカラー変数には数値や文字列をひとつだけ代入することができます。

my $xx = 5;          # スカラー変数$xxに数値5を代入
my $yy = "abc";      # スカラー変数$yyに文字列abcを代入
print "$xx $yy\n";    # スカラー変数$xxと$yyの値を表示
配列(@XXX)

アットマーク(@)で始まる変数は配列と呼ばれます。配列は複数の値を持つことができます。配列の個々の値を要素と呼びます。$配列[添え字] で個々の配列要素を参照することができます。添え字は 0 からはじまる整数です。

my @xx = (123, 12.3, "ABC");      # 配列@xxを定義して、123 と 12.3 と "ABC" を代入
print "$xx[0]\n";                 # => 123
print "$xx[1]\n";                 # => 12.3
print "$xx[2]\n";                 # => ABC

配列には下記の様にして要素を代入することができます。

my @xx = (123, 12.3, "ABC");
$xx[0] = 234;               # 0番目の要素に234を代入
@xx[1..2] = (23.4, "XYZ");  # 1番目の要素に23.4、2番目の要素に"XYZ"を代入
print "$xx[0]\n";           # => 234
print "$xx[1]\n";           # => 23.4
print "$xx[2]\n";           # => XYZ

$#変数名 は、@変数名 の配列の最後の添え字(個数から1をひいたもの)を表わします。

my @xx = ( "A", "B", "C", "D" );
print "$#xx\n";                     # => 3

@変数名 をスカラ値として参照すると配列の個数を返します。

my @xx = ( "A", "B", "C", "D" );
my $num = @xx;
print "$num\n";                     # => 4

配列を用いて複数の変数に一括して代入することもできます。

my ( $year, $mon, $day ) = ( 2023, 9, 24 );
print "$year/$mon/$day\n";         # => 2023/9/24

()は空配列を示します。

my @xx = ();          # 0個の要素を持つ配列

配列を操作するためのいろいろな関数が用意されています。

shift(@xx);           # 最初の要素を取り除き、これを返す
pop(@xx);             # 最後の要素を取り除き、これを返す
push(@xx, $xx);       # 最後に要素を追加する
push(@xx, @xx2);      # 最後に配列の値を追加する
splice(@xx, 3, 2);    # $xx[3..4](2個)を取り除き、これを返す
reverse(@xx);         # @xxの要素を逆順にしたものを返す
sort(@xx);            # @xxの要素をソートした結果を返す

すべての配列要素について処理を行うには foreach を用います。

my @xx = ("A", "B", "C", "D", "E");
foreach my $i (@xx) {
    print "$i\n";
}
ハッシュ(%XXX)

パーセント(%)ではじまる変数は ハッシュ と呼ばれます。ハッシュは文字列を添え字とした複数の値を持つことができます。連想配列 と呼ばれることもあります。

my %xx;                       # ハッシュ %xx を定義
$xx{"Tanaka"} = "male";
$xx{"Suzuki"} = "female";
print $xx{"Tanaka"}. "\n";    # => male
print $xx{"Suzuki"}. "\n";    # => female

次の様に初期化することもできます。

my %xx = (
    "Tanaka" => "male",
    "Suzuki" => "female",
);
print $xx{"Tanaka"}. "\n";    # => male
print $xx{"Suzuki"}. "\n";    # => female

while を用いてすべてのハッシュ要素に対して処理を行うことができます。

while (my ($key, $value) = each(%xx)) {
    print "$key = $value\n";
}
変数名に使える文字

変数名にはアンダーバー( _ )を含む半角英数文字を使用することができます。最初の1文字は数値であってはなりません。

$my-name       # × ハイフン( - )は使用できない
$32xx          # × 数値で始まってはならない

大文字の変数名と小文字の変数名は別の変数として扱われます。

my $xx = 123;
my $XX = 456;

$変数名、@変数名、%変数名 はそれぞれ個別の名前空間をもっているので、$xx と @xx と %xx はそれぞれ別の変数になります。

my $xx = 123;
my @xx = ("A", "B", "C");
my %xx = ("A" => "a", "B" => "b");
定義済変数みと未定義変数

変数には定義済みの状態と未定義の状態があります。最初は未定義ですが、最初に何か値が代入されると定義済みになります。定義済みかどうかを調べるためにdefined()を使用できます。

my $xx = 123;
if (defined($xx)) {
    print "Defined\n";
} else {
    print "Not defined.\n";
}
省略時の変数($_)

perlには省略の美学というものがあり、いろいろな箇所で変数名を省略することができます。省略した場合は、$_ を指定したものとみなされます。

while (<IN>)    # while ($_ = <IN>) と同じ意味
print;          # print $_; と同じ意味
if (/^From:/)   # $_ =~ /^From:/ と同じ意味

これを用いて、

while ($xx = <IN>) {
    if ($xx =~ /^From:/) { print $xx; }
}

というコードは、次のように書くことができます。

while (<IN>) {
    if (/^From:/) { print; }
}
環境変数($ENV{'XXX'})

%ENV は環境変数の値を持つハッシュです。

print $ENV{"PATH"};           # 環境変数PATHの値を表示する
$ENV{"TZ"} = "Asia/Tokyo";    # 環境変数TZに値を設定する
コマンド引数($ARGV)

@ARGV はコマンドラインからの引数をもつ配列です。

@ARGV           # 引数の配列
$#ARGV          # 配列の個数 - 1
$ARGV[0]        # 最初の引数
$ARGV[$#ARGV]   # 最後の引数
シグナル($SIG{'XXX'})

%SIG はシグナルハンドラを制御するハッシュです。下記の例では Ctrl-C で SIGINT シグナルをうけとると sigint サブルーチンを呼び出し、SIGINT!!! と表示してプログラムを終了させます。

sub sigint {
    print "SIGINT!!!\n";
    exit;
}

$SIG{"INT"} = "sigint";
その他の特殊変数($X)

他にも次のような特殊変数があります。

$.       # ファイルから読み込み時の現在の行数
$/       # 入力時のレコード区切り文字。通常は改行。
$,       # 出力時の項目区切り文字。print @xx; の時に有効
$"       # 出力時の項目区切り文字。print "@xx"; の時に有効
$\       # 出力時の行末文字。print "$xx"; の後ろに付加される
$#       # 出力時の数値形式。通常は"%.20g"。詳細はprintfを参照
$%       # 出力時の現在のページ番号
$=       # 出力時の現在のライン数
$-       # 出力時の残り行数
$~       # 出力時のフォーマット名(デフォルトはハンドル名と同じ)
$^       # 出力時のヘッダフォーマット名
$|       # 0以外が代入されると出力をバッファリングしなくなる。
$$       # プロセスID
$?       # 最後に実行されたコマンドのステータス
$&       # パターンマッチにマッチした部分文字列
$`       # パターンマッチにマッチした部分の前側の文字列
$'       # パターンマッチにマッチした部分の後側の文字列
$+       # パターンマッチの最後の()に対応する文字列
$*
$0       # perlスクリプトのコマンド名
$1       # パターンマッチの際の1番目の()に対応する文字列
$[       # 配列の最初の添え字。通常は0。
$]       # perlのバージョン情報
$;       # 高次元ハッシュの添え字の区切り文字
$!       # エラー番号、もしくはエラー文字列
$@       # 直前のevalコマンドのエラーメッセージ
$<       # このプロセスの実ユーザーID
$>       # このプロセスの実効ユーザーID
$(       # このプロセスの実グループID
$)       # このプロセスの実効グループID
$
$^D      # デバッグフラグの値
$^F      # システムファイルディスクリプタの最大値
$^I      # -iオプションで指定した拡張子の名前
$^L
$^P      # デバッガが使用する内部フラグ
$^T      # スクリプトを実行した時刻
$^W      # 警告スイッチの現在値
$^X      # perl自身の起動時の名前
@_       # サブルーチンへの引数
@INC     # perlライブラリ検索ディレクトリ
%INC     # 読み込まれたライブラリファイルの配列
__LINE__ # スクリプト中の現在の行数
__FILE__ # スクリプトのファイル名

演算子

代入演算子

次の例は「$xxは5である」という意味ではなく、「変数$xxに値5を代入する」という意味を持ちます。

$xx = 5;
算術演算子

下記の算術演算子を使用することができます。

$xx = 5 + 2;        # 足し算
$xx = 5 - 2;        # 引き算
$xx = 5 * 2;        # 掛け算
$xx = 5 / 2;        # 割り算
$xx = 5 % 2;        # 5を2で割った余り(=1)
$xx = 5 ** 2;       # 5の2乗(=25)

下記の様に演算と代入をまとめておこなうことができます。

$xx += 2;           # $xx = $xx + 2; と同じ
$xx -= 2;           # $xx = $xx - 2; と同じ
$xx *= 2;           # $xx = $xx * 2; と同じ
$xx /= 2;           # $xx = $xx / 2; と同じ
$xx %= 2;           # $xx = $xx % 2; と同じ
$xx **= 2;          # $xx = $xx ** 2; と同じ

下記の例のように $xx の値をひとつ増やしたり、減らしたりすることができます。

$xx++;              # インクリメント。$xxの値が1加算されます
$xx--;              # デクリメント。$xxの値が1減算されます
ビット演算子

下記のビット演算子を使用することができます。

printf("%04x\n", 0xff00 | 0x00ff);    # => ffff (OR)
printf("%04x\n", 0xfff0 & 0x0fff);    # => 0ff0 (AND)
printf("%16x\n", ~0xff00);            # => ffffffff00000000 (NOT)
printf("%04x\n", 0x00ff << 8);        # => ff00 (8ビット左シフト)
printf("%04x\n", 0xff00 >> 8);        # => 00ff (8ビット右シフト)

下記も使用できます。

$xx |= 0x00ff;          # $xx = $xx | 0x00ff と同じ
$xx &= 0x0fff;          # $xx = $xx & 0x0fff と同じ
$xx <<= 8;              # $xx = $xx << 8 と同じ
$xx >>= 8;              # $xx = $xx >> 8 と同じ
数値比較演算子

if文やwhile文の中で数値に対する条件判断を行うには、次のような比較演算子を用います。

if ($xx == $yy)            # $xxと$yyが等しければ
if ($xx != $yy)            # $xxと$yyが等しくなければ
if ($xx < $yy)             # $xxが$yyより小さければ
if ($xx > $yy)             # $xxが$yyより大きければ
if ($xx <= $yy)            # $xxが$yyより小さいか等しければ
if ($xx >= $yy)            # $xxが$yyより大きいか等しければ

下記の様に「かつ」や「もしくは」を表すことができます。

if (($xx==2) && ($yy==3))  # $xxが2、かつ、$yyが3であれば
if (($xx==2) || ($yy==3))  # $xxが2、もしくは、$yyが3であれば

下記の演算子は、$xx と $yy を比較して、$xx が小さければ -1 を、等しければ 0 を、大きければ 1 を返します。

$xx <=> $yy                # 比較結果を -1, 0, 1 のいずれかで返す
文字列比較演算子

文字列に対しては次のような演算子を用います。

if ($xx eq $yy)            # $xxと$yyが等しければ (EQual)
if ($xx ne $yy)            # $xxと$yyが異なっていれば (Not Equal)
if ($xx lt $yy)            # $xxが$yyより辞書順に小さければ (Less Than)
if ($xx gt $yy)            # $xxが$yyより辞書順に大きければ (Greater Than)
if ($xx le $yy)            # $xxが$yyより等しいか辞書順に小さければ (Less than or Equal)
if ($xx ge $yy)            # $xxが$yyより等しいか辞書順に大きければ (Greater than or Equal)
if ($xx cmp $yy)           # 比較し、-1, 0, 1 のいずれかで返す
条件演算子

A ? B : C は、A が真であれば B を、偽であれば C を値とします。下記の例では $yy の値が5未満であれば "small" を、さもなくば "big" を $xx に代入します。

$xx = ($yy < 5) ? "small" :  "big";
正規表現マッチング

変数 $xx の文字列が 正規表現 にマッチするか否かを調べます。

if ($xx =~ /[a-z]+/)        # 正規表現にマッチすれば
if ($xx !~ /[a-z]+/)        # 正規表現にマッチしなければ

置換文字列の中に括弧を書くと、その括弧に対応した文字列を $1, $2, ... で参照することができます。次の例は、12:34:56 の秒数を求めます。

my $xx = "12:34:56";
if ($xx =~ /([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/) {
    print $1 * 3600 + $2 * 60 + $3;      # => 45296
}
文字列連結

文字列を連結します。

$xx = $yy . $zz;    # 文字列 $yy と 文字列 $zz を連結します
$xx .= $yy;         # $xx = $xx . $yy と同様です。
文字列置換

変数名 =~ s/expr/str/ は、変数に格納された文字列の中の正規表現 expr にマッチする部分を文字列 str に置換します。下記の例では、文字列 $xx の中の abc にマッチする部分を ABC に置換します。

my $xx = "abcdefg";
$xx =~ s/abc/ABC/;     # => ABCdefg

正規表現の中に (...) を使用すると (...) に対応する文字列を $1, $2, $3,...で参照することができます。次の例は、"12:34:56" を "12時34分56秒" に置換します。

my $xx = "12:34:56";
$xx =~ s/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/$1$2$3秒/;

g オプションは、見つかった箇所をすべて置換します。g オプションをつけない場合は最初の1回のみを置換します。

my $xx1 = "abcabcabc";
my $xx2 = "abcabcabc";
$xx1 =~ s/abc/ABC/;         # => ABCabcabc (最初の1回のみ置換)
$xx2 =~ s/abc/ABC/g;        # => ABCABCABC (見つかったものすべてを置換)

i オプションは大文字と小文字を区別せずにマッチングします。

my $xx1 = "abcABC";
my $xx2 = "abcABC";
$xx1 =~ s/ABC/XYZ/g;         # => abcXYZ (ABCのみにマッチ)
$xx2 =~ s/ABC/XYZ/gi;        # => XYZXYZ (abcにもABCにもマッチ)

e オプションは、str の部分を文字列ではなく perlの実行文と解釈してその結果に置換します。次の例は、12:34:56を秒数に置換します。

my $xx = "12:34:56";
$xx =~ s/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/$1*3600+$2*60+$3/e;   # => 45296

正規表現の中でスラッシュ(/)を使用する際は、バックスラッシュ(\)でエスケープする必要があります。下記の例は /usr/bin/perl を /usr/local/bin/perl に置換しています。

$xx =~ s/\/usr\/bin\/perl/\/usr\/local\/bin\/perl/;

s/.../.../ の代わりに s|...|...| を使用すると / をそのまま記述することができます。| の代わりに ' や ! など他の記号文字を使用することができます。

$xx =~ s|/usr/bin/perl|/usr/local/bin/perl|;

str に変数を使用すると変数の値に展開されます。ただし s'...'...' の場合は展開されません。

my $xx1 = "abc";
my $xx2 = "abc";
my $yy = "ABC";
$xx1 =~ s/abc/$yy/;    # => ABC
$xx2 =~ s'abc'$yy';    # => $yy

次の例は、URLエンコードされた %20 のような文字列をデコードします。CGIなどではよく使用される構文です。

my $xx = "%41%42%43";          # "ABC"のASCIIコード
$xx =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;   # => ABC
繰り返し演算子

x は繰り返し演算子と呼ばれます。

print "a" x 5;       # "aaaaa"
$xx x= 5;            # $xx = $xx x 5 と同じ
@xx = (1) x 5;       # (1, 1, 1, 1, 1)
@xx = (1, 2) x 5;    # (1, 2, 1, 2, 1, 2, 1, 2, 1, 2)
範囲演算子

.. は配列の範囲を示します。

@xx = (1 .. 5);     # @xx = (1, 2, 3, 4, 5);と同じ
for (1 .. 5)        # for ($_ = 1; $_ <= 5; $_++) と同じ
ファイル検査

次のようにして、ファイルが読み込み、書き込み可能かどうかなどを検査することができます。

if (-r "file.txt") { print "読み込み可能\n"; }
if (-w "file.txt") { print "書き込み可能\n"; }

アンダーライン(_)は最後に検査されたファイルを示します。

if (-r "file.txt") { print "読み込み可能\n"; }
if (-w _) { print "書き込み可能\n"; }

ファイルハンドルに対して検査することもできます。

open(my $in, "<", "file.txt");
if (-r $in) { print "読み込み可能\n"; }
close($in);

stat() の結果に対してアンダーライン(_)で検査することもできます。

stat("file.txt");
if (-r _) { print "読み込み可能\n"; }

-r や -w の他にも次のような検査が可能です。

-r      # 読み込み可能であれば
-w      # 書き込み可能であれば
-x      # 実行可能であれば
-o      # 自分のものであれば
-R      # 実uid/gidで読み込み可能であれば
-W      # 実uid/gidで書き込み可能であれば
-X      # 実uid/gidで実行可能であれば
-O      # 実uidのものであれば
-e      # 存在すれば
-z      # サイズが0であれば
-s      # サイズが0でなければ(ファイルサイズを返す)
-f      # 通常ファイルであれば
-d      # ディレクトリであれば
-l      # シンボリックリンクであれば
-p      # 名前付きパイプであれば
-S      # ソケットであれば
-b      # ブロック型スペシャルファイルであれば
-c      # キャラクタ型スペシャルファイルであれば
-u      # setuidビットが立っていれば
-g      # setgifビットが立っていれば
-k      # stickyビットが立っていれば
-t      # ファイルハンドルが tty としてオープンされていれば
-T      # ファイルがテキストファイルであれば
-B      # ファイルがバイナリファイルであれば
-M      # perl起動時における、ファイルの更新時刻からの日数
-A      # perl起動時における、ファイルの参照時刻からの日数
-C      # perl起動時における、ファイルの作成時刻からの日数

制御構文

if elsif else文

if (...) {...} は (...) が真の場合のみ {...} を実行します。

my $xx = 5;
if ($xx == 5) {
    print "等しい\n";
}

else は「さもなくば」を意味します。

my $xx = 5;
if ($xx == 5) {
    print "等しい\n";
} else {
    print "等しくない\n";
}

elsif は「さもなくばもし」を意味します。

my $xx = 5;
if ($xx > 5) {
    print "5より大きい\n";
} elsif ($xx < 5) {
    print "5より小さい\n";
} else {
    print "5と等しい\n";
}
unless文

unless (...) {...} は (...) が偽の場合に {...} を実行します。

my $xx = 4;
unless ($xx > 5) {
    print "5より大きくない\n";
}
while文

while (...) {...} は、(...) が真のあいだ {...} を繰り返し実行します。

my $xx = 1;
while ($xx < 10) {
    print "xx = $xx\n";
    $xx++;
}
until文

until (...) {...} は、(...) が真になるまで {...} を繰り返し実行します。

my $xx = 1;
until ($xx > 10) {
    print "xx = $xx\n";
    $xx++;
}
do文

do {...} を用いて、if (...), unless (...), while (...), until (...) を下記の様に記述することができます。

do { print "xx = $xx\n"; } if ($xx == 5);
do { print "xx = $xx\n"; } unless ($xx == 5);
do { print "xx = $xx\n"; $xx++; } while ($xx < 5);
do { print "xx = $xx\n"; $xx++; } until ($xx > 5);
do {...} の中身が単文の場合、do { ; } を省略することができます。
print "xx = $xx\n" if ($xx == 5);
print "xx = $xx\n" unless ($xx == 5);
print "xx = $xx\n" while ($xx++ < 5);
print "xx = $xx\n" until ($xx++ > 5);
for文

for (expr1; expr2; expr3) {...}expr1 を実行し、expr2 が真の間、expr3 と {...} を実行します。下記の例では、$i に 1 を代入し、$i が 10 より小さい間、$i をインクリメントしながら print を実行します。

for (my $xx = 1; $xx < 10; $xx++) {
    print "xx = $xx\n";
}

次の様に書くこともできます。

my @xx = (1, 2, 3, 4, 5, 6, 7, 8, 9);
for (@xx) {
    print "xx = $_\n";
}

次の様に書くこともできます。

for (1..9) {
    print "xx = $_\n";
}
foreach文

foreach var (...) {...} は配列の各要素を var に代入しながら {...} の処理を行います。

my @xx = ( "A", "B", "C" );
foreach my $x (@xx) {
    print "x = $x\n";
}
last文

last は、最も内側のループを抜けます。

my $xx = 1;
while ($xx < 10) {
    if ($xx == 5) {
        last;
    }
}
next文

next は、最も内側のループを繰り返します。

open(my $in, "<", "file.txt");
while (my $line = readline($in)) {
    if ($line =~ /^#/) {
        next;
    }
    print $line;
}
close($in);
continue文

continue {...} は、ループを繰り返す際の処理を記述します。例えば次の2つのコードは同じ動作となります。

for (my $xx = 1; $xx < 10; $xx++) {
    print "$xx\n";
}
my $xx = 1;
while ($xx < 10) {
    print "$xx\n";
} continue {
    $xx++;
}

入出力

ファイル読み込み

ファイルからの読み込みは次のようにします。ここで、IN のような変数をファイルハンドルと呼びます。ファイルハンドルは IN でも HEHE でも好きな名前で構いませんが通常大文字にします。ファイルを読み書きする際は、このファイルハンドルを指定します。

open(IN, "file.txt");
while ($line = <IN>) {
    print $line;
}
close(IN);

変数 $line を省略した場合は、省略時の暗黙の変数 $_ が使用されます。前記の例は次のように記述することもできます。

open(IN, "file.txt");
while (<IN>) {
    print;
}
close(IN);

これは、次の記述と同じ意味を持ちます。

open(IN, "file.txt");
while ($_ = <IN>) {
    print $_;
}
close(IN);

もっと簡単に次のように記述することもできます。

open(IN, "file.txt");
print <IN>;
close(IN);

次のようにファイルの各行を配列に一括して読み込むこともできます。

open(IN, "file.txt");
my @lines = <IN>;
foreach my $line (@lines) {
    print $line;
}
close(IN);

ファイルを開けない時にエラー終了させるには次のようにします。

open(IN, "file.txt") or die "Can't open file\n";

ファイルハンドルを省略すると、標準入力、またはコマンドラインで指定したファイルをひとつづつオープンし、それを順次読み込むことができます。

while (<>) {
    print;
}

ファイル指定の場合は次のような処理と同等になります。

for (my $i = 0; $i <= $#ARGV; $i++) {
    open(IN, $ARGV[$i]);
    while (<IN>) {
        print;
    }
    close(IN);
}

IN などのファイルハンドルはグローバル変数の様に扱われてしまうため、Perl 5.6 からはファイルハンドルとして my で宣言するローカル変数を使用できるようになりました。

open(my $in, "file.txt");
while (my $line = readline($in)) {
    print $line;
}
close($in);
ファイル書き込み

ファイルに書き込むには次のようにします。

open(OUT, "> file.txt");
print(OUT "ABC\n");
close(OUT);

ファイルに追加書き込みするには次のようにします。

open(OUT, ">> file.txt");
print(OUT "こんにちわ\n");
close(OUT);

ファイルを読み書きモードで開くには次のようにします。

open(FH, "+< file.txt");      # 読み書きモード (ファイルが存在しなければエラー/ファイルの先頭から上書き)
open(FH, "+> file.txt");      # 読み書きモード (ファイルが存在しなければ作成/ファイルサイズを0にする)
open(FH, "+>> file.txt");     # 読み書きモード (ファイルが存在しなければ作成/ファイルの末尾から追記)

最近の Perl では ">" などのモードを第二引数として指定できるようになりました。ファイルハンドルも my 変数を使用した方がベターです。

open(my $fh, ">", "file.txt");
open(my $fh, ">>", "file.txt");
open(my $fh, "+<", "file.txt");
open(my $fh, "+>", "file.txt");
open(my $fh, "+>>", "file.txt");
外部コマンド実行

出力結果を外部コマンドに渡すこともできます。次の例ではprint文の出力を sort に渡してソートします。

open(OUT, "| /usr/bin/sort");
print OUT "BBB\n";
print OUT "CCC\n";
print OUT "AAA\n";
close(OUT);

外部コマンドの出力結果を読み取ることもできます。次の例では、file.txt の中身を nkf コマンドでEUCに変換したデータを読み込みます。

open(IN, "/usr/bin/df |");
while (<IN>) {
    print;
}
close(IN);

単に外部コマンドを実行するだけであれば、次のようにします。

system("/usr/bin/df");
標準入出力

次の3つのファイルハンドルがあらかじめオープンされています。

STDIN     標準入力
STDOUT    標準出力
STDERR    標準エラー出力

標準入力から各行を読み込むには次のようにします。

while (<STDIN>) {
    print;
}

STDIN を省略すると、コマンド引数で何も指定しなかった場合は標準入力から、コマンド引数でファイルのリストを指定した場合は、そのファイルを順次読み取ることができます。

while (<>) {
    print;
}
改行コード

改行コードは、Linux などの UNIX系システムでは LF(\n)、Windowsでは CR LF(\r\n)、Mac は Mac OS 9 までは CR(\r) でしたが、Mac OS X 以降は LF(\n) のように異なります。入力ファイルの改行コードの差異に関わらず、動作環境に合わせた改行コードに変換するには下記の様にします。

while (my $line = readline($in)) {
    $line =~ s/[\r\n]*$//;
    print "$line\n";
}
テキストモード・バイナリモード

前述の例で Windows では $_\n ではなく $_\r\n にすべきだと思うかもしれませんが、Windows は STDOUT やファイルへの出力は \n を \r\n に自動変換して書き込みます。これを テキストモード と呼びます。この自動変換を行わないようにするには binmode() を用いて バイナリモード にします。

open(my $in, "<", "infile.txt");
open(my $out, ">", "outfile.txt");
binmode($out);         # 出力をバイナリモードにする(Windowsで\nを\r\nに変換しない)
while (my $line = readline($in)) {
    $line =~ s/[\r\n]*$//;
    print $out "$line\n";
}
close($in);
close($out);
バイナリ読み込み

次のようなコードでファイルをバイナリデータとして読み込む事ができます。

open(my $in, "binary.dat");         # ファイルを開く
binmode($in);                       # バイナリモードで読み書きする
my $size = -s "binary.dat";         # ファイルサイズを得る
sysread($in, my $buf, $size);       # ファイルサイズ分バイナリモードで読み込む
close($in);                         # ファイルをクローズする
my @data = unpack("C*", $buf);      # バイナリデータを数値配列に変換する
for my $x (@data) {
    printf("%02x ", $x);            # 1バイトずつ16進数で表示する
}
print "\n";

サブルーチンとライブラリ

サブルーチン(sub)

次のようにしてサブルーチンを宣言することができます。

sub add {
    return($_[0] + $_[1]);
}

サブルーチンは宣言しただけでは実行されませんが、次のように呼び出す事によって実行されます。

print add(3, 5);

サブルーチンに渡された引数は特殊配列変数 @_ に格納され、$_[0], $_[1], $_[2], ...で参照することができます。下記の様にすると、第一引数を $x、第二引数を $y の名前で受け取れるようになります。

sub add {
    my ($x, $y) = @_;
    return $x + $y;
}
print add(3, 5) . "\n";

return(...) は ... をサブルーチンの戻り値として返し、サブルーチンを終了します。

sub add {
    my ($x, $y) = @_;
    return $x + $y;
}

return() を省略した場合は、サブルーチンの最後の文(statement)の結果がサブルーチンの戻り値となります。

sub add {
    my ($x, $y) = @_;
    $x + $y;
}
変数のスコープ

my で宣言した変数はそのブロック内でのみ有効です。{...} の外部で定義した $xx と内部で定義した $xx は別の変数として扱われます。

my $xx = "ABC";         # グローバル変数
{
    my $xx = "XYZ";     # ローカル変数 ({...}内のみで有効)
    print "$xx\n";      # => XYZ (ローカル変数)
}
print "$xx\n";          # => ABC (グローバル変数)
参照渡し

サブルーチンに複数の配列を渡す場合、下記の様に渡すと (1, 2, 3, 4, 5, 6) というひとつの配列に結合されてしまいます。

sub printList {
    foreach my $x (@_) { print "$x "; }    # => 1, 2, 3, 4, 5, 6
    print "\n";
}
my @a = (1, 2, 3);
my @b = (4, 5, 6);
printList(@a, @b);

複数の配列として渡すには参照渡しという仕組みを用います。呼び出し側は \@変数名 で配列への参照(ポインタ)を渡します。受け取り側は参照(ポインタ)を $変数名 で受け取り、@$変数名 で元の配列を参照します。

sub printList {
    my ($list1, $list2) = @_;
    foreach my $x (@$list1) { print "$x "; }    # => 1, 2, 3
    print "\n";
    foreach my $x (@$list2) { print "$x "; }    # => 4, 5, 6
    print "\n";
}
my @a = (1, 2, 3);
my @b = (4, 5, 6);
printList(\@a, \@b);
ライブラリ

別ファイルにライブラリとしてサブルーチンなどを定義することができます。下記の内容のファイルを ~/lib/mycalc.pl として保存してください。ファイルの末尾に 1; など真と見なされる値を記述する必要があります。

sub add {
    my ($x, $y) = @_;
    return $x + $y;
}
1;

環境変数 PERLLILB にライブラリファイルを配置するディレクトリを指定してください。

$ export PERLLIB=~/lib

reuqire を用いてライブラリファイルを読み込み、ライブラリ内のサブルーチンを呼び出すことができます。

require "mycalc.pl";
print add(3, 5) . "\n";

サブルーチン名の重複を避けるために、パッケージ名を指定することができます。~/lib/mycalc.pl に package 定義を追加します。

package mycalc;
sub add {
    my ($x, $y) = @_;
    return $x + $y;
}
1;

呼び出し側もパッケージ名をつけて呼び出します。

require "mycalc.pl";
print mycalc'add(3, 5) . "\n";

その他

コメント(#)

ハッシュ記号(#)から行末まではコメントとして無視されます。

$xx = 5;    # ここから行末までは無視されます
正規表現

次の例の /EFG/ などのように、Perlでは文字列の特徴を 正規表現 として表現することができます。

my $xx = "ABCDEFG";
if ($xx =~ /EFG/) {          # 文字列$xxが文字列EFGを含んでいたら
    print "含んでいる\n";
}

上記の if文は「変数$xxの中にEFGという文字列が含まれていたら」という意味になります。詳細は「とほほの正規表現入門」を参照してください。

A           Aという文字
ABC         ABCという文字列
A+          1個以上連続したA(A, AA, AAA, ...)
A*          0個以上連続したA(  , A, AA, AAA, ...)
A?          0または1つのA(  , A)
A{3}        3個のA
A{3,}       3個以上のA
A{3,5}      3個以上5個以下のA
.           1つの任意文字(A, B, C, ...) (\nを除く)
^ABC        ABCで始まっていたら
ABC$        ABCで終わっていたら
[ABC]       A,B,Cのいずれか1文字
[A-Z]       A~Zまでのいずれか1文字
[A-Za-z0-9] A~Z, a~z, 0-9までのいずれか1文字
[^ABC]      A,B,C以外の文字
[^A-Z]      A~Z以外の文字
A|B|C       AまたはBまたはC
\w          英数文字かアンダーバー( _ )。[a-zA-Z0-9_]と同様
\W          \w以外の文字
\d          数値文字。[0-9]と同等
\D          \d以外の文字
\s          空白文字
\S          \s以外の文字
\b          単語の区切り??????
\B          \b以外の文字
\n          エスケープシーケンス文字の\n
(ABC)       ABCという文字列。カッコ部分は後で参照可能です。

これらを組み合わせてたとえば、「perlの変数名に用いることができる名前」は次のように表わされます。

^[A-Za-z_][A-Za-z0-9_]*$

正規表現中では下記の文字は特殊な文字(メタ文字)として扱われます。これらの文字を表わすには \+, \*, \?, ...のようにバックスラッシュ(\)でエスケープします。

+ * ? . ( ) [ ] { } | \

括弧(...)で囲んだ部分は、正規表現内では \1, \2, \3, ...として参照できます。1, 2, 3, ...は、正規表現中で括弧が現れる順番を示します。

^(...)\1    最初の3文字がもう一度繰り返す(ABCABCなど)

また、正規表現の外ではマッチの結果を次のように参照できます。

$1, $2, $3, ...      (  )の部分にマッチした文字列
$+                   最後にマッチした(  )部分
$&                   マッチした部分の文字列
$`                   マッチした部分から前側の文字列
$'                   マッチした部分から後側の文字列

たとえば、次のように使用することができます。

if ($time =~ /^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$/) {
    $hour = $1;
    $min = $2;
    $sec = $3;
}
ヒアドキュメント

ヒアドキュメント を用いて複数行の文字列を表現することができます。下記の例は 3行の Hello world! を表示します。EOD は END_OF_DATA でも OWARI でもどんな文字列でも使用できますが、(1)<<の後にスペースをいれてはならない、(2)最初のEND_OF_DATAの後ろにはセミコロン(;)が必要、(3)最後のEND_OF_DATAの後ろには改行が必要、など注意点も多いので気を付けてください。

print <<EOD;
Hello World!
Hello World!
Hello World!
EOD

次の例では、変数 $msg に 3行のメッセージを代入しています。

my $msg = <<EOD;
This is Japan.
That is America.
That is England.
EOD
print $msg;

最初の EOD を EOD としたり "EOD" のようにダブルクォート(")で囲む場合は文字列の中で変数が展開されます。下記の例では Hello Tanaka! が3行表示されます。

my $name = "Tanaka";
print <<"EOD";
Hello $name!
Hello $name!
Hello $name!
EOD

EOD をシングルクォート(')で囲む場合は変数の展開は行われません。下記の例では Hello $name! が3行表示されます。

my $name = "Tanaka";
print <<'EOD';
Hello $name!
Hello $name!
Hello $name!
EOD
リファレンス

Perl5からはC言語のポインタに相当するリファレンスがサポートされました。\$xx, \@xx, \%xx はそれぞれの変数へのリファレンスを示します。リファレンスに $, @, % をつけるとリファレンス先の値を得ることができます。

my $num1 = 123;
my $num_ref = \$num1;
my $num2 = $$num_ref;
print "$num2\n";

my @arr1 = ("A", "B", "C");
my $arr_ref = \@arr1;
my @arr2 = @$arr_ref;
print @arr2;
print "\n";

my %hash1 = ( "height" => 123, "width" => 456 );
my $hash_ref = \%hash1;
my %hash2 = %$hash_ref;
print $hash2{"height"} . ", " . $hash2{"width"} . "\n";

-> を用いてリファレンスから直接リファレンス先の値を参照することもできます。

my @arr1 = ("A", "B", "C");
my $arr_ref = \@arr1;
print $arr_ref->[0] . "\n";

my %hash1 = ( "height" => 123, "width" => 456 );
my $hash_ref = \%hash1;
print $hash_ref->{"height"} . "\n";

{...} はハッシュへのリファレンスを返します。

my $xx = { name => "Yamada", age => 26 };
print $xx->{"name"} . "\n";             # => Yamada

下記の様な複雑なデータを表すこともできます。

my $person = {
    name => {
        first_name => "Taro",
        last_name => "Yamada",
    },
    address => {
        prefecture => "Tokyo",
        city => "Minato-ku",
    }
};
print $person->{"name"}->{"last_name"} . "\n";

ハッシュリファレンスと配列を組み合わせることにより、構造体配列のようなものを表現することができます。

my @persons = ();
push @persons, { "name" => "Tanaka", "age" => 24 };
push @persons, { "name" => "Suzuki", "age" => 28 };
foreach my $person (@persons) {
    print "$person->{"name"} $person->{"age"}\n";
}
日本語の取り扱い

日本語には、シフトJIS、EUC、JIS(ISO-2022-JP)、UTF-8 などいくつかの文字コードがあります。Windows はまだ Shift_JIS 系と UTF-8 が混在していますが、UTF-8 を使用するケースが増えてきました。Perl で UTF-8 を扱うには下記のおまじないを行います。

use utf8;

標準入出力で日本語を扱う場合は下記を追加します。

use utf8;
binmode STDIN, ":encoding(utf-8)";
binmode STDOUT, ":encoding(utf-8)";
binmode STDERR, ":encoding(utf-8)";
print "あいうえお\n";

日本語のファイルを読み書きするにはモードにエンコーディングルールを指定します。次の例では UTF-8 のファイルを読み込み、Shift_JIS のファイルに書き込んでいます。文字コードには utf-8, Shift_JIS, ISO-2022-JP, EUC-JP などを指定できます。

use utf8;
binmode STDIN, ":encoding(utf-8)";
binmode STDOUT, ":encoding(utf-8)";
binmode STDERR, ":encoding(utf-8)";

open(my $in, "<:encoding(utf-8)", "file.txt");
open(my $out, ">:encoding(Shift_JIS)", "out.txt");
while (my $line = readline($in)) {
    print $out $line;
}
close($in);
close($out);

文字コードを変換するには Encode モジュールを使用します。

use Encode;
$str = Encode::decode("utf-8", $str);   # 外部コード文字列(UTF-8)を内部コード文字列にデコード
$str = Encode::encode("utf-8", $str);   # 内部コード文字列を外部コード文字列(UTF-8)にエンコード
Perlのバージョン指定

use v... を指定すると最低限必要とする perl のバージョンを指定することができます。

use v5.34;

Copyright (C) 1997-2023 杜甫々
初版:1997年2月3日、最終更新:2023年9月24日
http://www.tohoho-web.com/perl/basic.html