制御

■ もし~であれば(if)

◆ もし~ならば(if文)

if は「もし」を意味します。(...) の中には条件式を書きます。下記の例では、もし $num の値が 5 であれば「5です。」を表示します。== は「数値が等しければ」を意味します。(→ 算術比較演算子

$num = 5;
if ($num == 5) {
    print "5です。\n";
}

条件節を後ろに書くという英語の文法にマッチするように、次のように記述することもできます。

$num = 5;
print "5です。\n" if ($num == 5);

if (...) { ... } の形式では、実行文が1行であっても、{ と } を省略することはできません。

■ もし~でなければ(unless)

◆ もし~(unless文)

unless は「もし~でなければ」を意味します。下記の例では、もし $num の値が 5 でなければ「5ではありません。」を表示します。

$num = 3;
unless ($num == 5) {
    print "5ではありません。\n";
}

if 文と同様、次のように記述することもできます。

$num = 3;
print "5ではありません。\n" unless ($num == 5);
ひとくちメモ

Perl では、数値と文字列で比較に使用する演算子が異なります。例えば、数値が等しいか比較する場合は if ($num == 5) { ... } のようにしますが、文字列が等しいか比較する場合は if ($str eq "ABC") { ... } を用います。

■ さもなくば(else)

◆ さもなくば(else文)

else は「さもなくば」を意味します。もし、$num の値が 5 であれば「5です。」を、さもなくば、「5ではありません。」を表示します。

$num = 3;
if ($num == 5) {
    print "5です。\n";
} else {
    print "5ではありません。\n";
}

else を unless に使用することもできます。訳がわからなくなりますが・・・。

unless ($num == 5) {
    print "5ではありません。\n";
} else {
    print "5でないことはないです。\n";
}

■ さもなくばもし(elsif)

◆ さもなくばもし(elsif文)

elsif は else if の略で、「さもなくば、もし」を意味します。$num の値が 5 であれば「5です。」を、6 であれば「6です。」を、7 であれば「7です。」を、さもなくば「5でも6でも7でもありません。」と表示します。

$num = 6;
if ($num == 5) {
    print "5です。\n";
} elsif ($num == 6) {
    print "6です。\n";
} elsif ($num == 7) {
    print "7です。\n";
} else {
    print "5でも6でも7でもありません。\n";
}

elsif はいくつでも記述することができます。C言語のように else if と書いてしまったり、elseif とスペルミスしないようにしましょう。

■ 処理を n回繰り返す(for)

◆ for文による方法(1)

for は繰り返しを処理します。まず $i に 0 を代入し、$i の値をひとつ加算しながら、$i の値が 10 未満である間、つまり、$i が 0 から 9 までの間、print 文を繰り返して実行します。

for ($i = 0; $i < 10; $i++) {
    print "i = $i\n";
}
◆ for文による方法(2)

これも、print 文を 10回繰り返します。$i は 1 から 10 までの値をとります。

for $i (1..10) {
    print "i = $i\n";
}

$i を省略して for (1..10) とすることもできます。この場合、$i の代わりに省略時変数 $_ が用いられます。

for (1..10) {
    print "i = $_\n";
}
◆ 無限ループ

for (;;) は無限にループを繰り返します。下記の例では、キーボードから q と入力するまで、永遠にループを繰り返します。

for (;;) {
    print "> ";
    $str =<>;
    chop($str);
    if ($str eq "q") {
        last;
    }
    print "$str\n";
}

■ 配列の処理を繰り返す(foreach)

◆ 配列処理(foreach文)

foreach は配列のそれぞれの要素に対して、ひとつずつ処理を行います。$name に "Tanaka", "Suzuki", "Yamada" を順に代入しながら処理を繰り返します。

@namelist = ( "Tanaka", "Suzuki", "Yamada" );
foreach $name (@namelist) {
    print "NAME = $name\n";
}

実行結果は次のようになります。

NAME = Tanaka
NAME = Suzuki
NAME = Yamada
◆ ループ変数の省略

$name を省略した場合は、$name の代わりに省略時変数 $_ が用いられます。

@namelist = ( "Tanaka", "Suzuki", "Yamada" );
foreach (@namelist) {
    print "NAME = $_\n";
}

ひとくちメモ

実は、for と foreach はまったく同じものです。for の代わりに foreach を、foreach の代わりに for を用いることもできます。一般に、配列操作の場合に foreach、その他の場合に for を用います。

■ ~の間処理を繰り返す(while)

◆ ~の間(while文)

while は (...) が真である間処理を繰り返します。下記の例では $num の値をひとつずつ増やしながら、$num が 10 より小さい間、処理を繰り返します。

$num = 0;
while ($num < 10) {
    print "$num\n";
    $num++;
}

次のように記述することもできます。この場合、(...) が偽であっても、必ず1度は処理が実行されます。

$num = 0;
do {
    print "$num\n";
    $num++;
} while ($num < 10);

■ ~になるまでの間処理を繰り返す(until)

◆ ~になるまでの間(until文)

until は (...) が真になるまでの間処理を繰り返します。下記の例では、$num が 10 になるまでの間、処理を繰り返します。

$num = 0;
until ($num == 10) {
    print "$num\n";
    $num++;
}

while 文と同様、次のように記述することもできます。この場合も、必ず1度は処理が実行されます。

$num = 0;
do {
    print "$num\n";
    $num++;
} until ($num == 10);

■ ループを途中で抜ける(last)

◆ ループを抜ける(last文)

last は、ループ(for、foreach、while、until)を途中で中断して抜けます。JavaScript や C言語の break文に相当します。下記の例では、$i の値が 5 の時に、ループをを抜けます。

for ($i = 0; $i < 10; $i++) {
    if ($i == 5) { last; }
    print "i = $i\n";
}

ループが多重にある場合は、もっとも内側のループを抜けます。

for ($i = 0; $i < 10; $i++) {
    for ($j = 0; $j < 10; $j++) {
        if ($j == 5) { last; }       # $j のループを抜ける
        print "i = $i, j = $j\n";
    }
}

■ 次のループを実行する(next)

◆ 次のループを実行(next文)

next はループ(for、foreach、while、until)の残りの処理をとばして、次のループを実行します。JavaScript や C言語の continue に相当します。下記の例では、$i が 5 の時に print 文を実行しないで次のループに移ります。

for ($i = 0; $i < 10; $i++) {
    if ($i == 5) { next; }
    print "i = $i\n";
}

ループが多重にある場合は、最も内側のループに対して next が実行されます。

for ($i = 0; $i < 10; $i++) {
    for ($j = 0; $j < 10; $j++) {
        if ($j == 5) { next; }       # $j のループを next する
        print "i = $i, j = $j\n";
    }
}

■ 現在のループを繰り返す(redo)

◆ 現在のループを繰り返し(redo文)

redo は最も内側のループの、今現在行っているループをもう一度繰り返します。redo を行ってもカウントアップしない点が next と異なります。あまり利用されていませんが、カウントを数えながら処理を再トライするさせる場合などには便利です。

redo.pl
print "1~5の数字を3つ入力してください。\n";
for ($n = 1; $n <= 3; $n++) {
    print "$n個目> ";
    $num[$n] = <STDIN>;
    chomp($num[$n]);
    if (($num[$n] < 1) || (5 < $num[$n])) {
        print "ちょっと変です。\n";
        redo;
    }
}
print "$num[1], $num[2], $num[3] ですね。\n";

■ 次のループの前処理(continue)

◆ 次のループの前処理(continue文)

continue { ... } には、while の次のループを実行する直前の処理を記述します。下記の例は for ($i = 0; $i < 5; $i++) { ... } と同じ動作となります。

$i = 0;
while ($i < 5) {
    print "$i\n";
} continue {
    $i++;
}

C言語にも continue 文がありますが、意味は異なります。C言語の continue は Perl の next に相当します。

■ ジャンプする(goto)

◆ ジャンプ(goto文)

goto 文は、ラベル名: の場所にジャンプします。下記の例では、phase 1 の処理を行った後、phase3 の箇所にジャンプします。

    print "phase 1.\n";
    goto phase3;
    print "phase 2.\n";
phase3:
    print "phase 3.\n";

プログラミングの本にはよく「goto 文を用いるとプログラムの流れが繁雑になるので、goto 文を用いるべきではない。」と書かれています。しかし、下記のようにエラー処理に限った使い方であれば非常に便利なので、このケースに限っては、私は goto 文を愛用しています。

goto.pl
$err = CopyFile("xx1.dat", "xx2.dat")) || print "$err\n";

# ファイルをコピーする
sub CopyFile {
    local($from, $to) = @_;
    local($err, *IN, *OUT, $line);

    if (!open(IN, $from)) {
        $err = "ファイル $from を開けません。\n";
        goto done;
    }
    if (!open(OUT, "> $to")) {
        $err = "ファイル $to を開けません。\n";
        goto done;
    }
    while ($line = <IN>) {
        if (!print OUT $line) {
            $err = "書き込みが失敗しました。\n";
            goto done;
        }
    }
done:    # 後処理をすべて done 以降に記述してしまう
    close(IN);
    close(OUT);
    return $err;
}

■ プログラムを途中で終了する(exit)

◆ プログラムを終了する(exit文)

exit はプログラムを途中で終了します。引数はプログラムの実行結果を返します。通常、プログラムが正常に終わるときには 0 を、プログラムが異常で終わるときには 0 以外の値を指定します。CGI の場合は、引数は無視されます。

if (!open(IN, $file)) {
    print "ファイルを開けませんでした。\n";
    exit(1);
}

UNIX では、プログラムの実行結果を次のようにして確認することができます。(csh 系シェルの場合)

% echo $status
0
%

■ プログラムを途中で終了する(die)

◆ プログラムを終了する(die文)

制御構文ではありませんが、die() もプログラムを終了します。加えて、終了時のメッセージを出力します。出力は標準エラー出力(STDERR)に行われますので、CGI ではあまり die を用いません。

open(IN, "data.txt") || die "data.txtを開けません。\n";

メッセージの末尾が改行でなければ、スクリプトファイル名と行番号が付加されます。

open(IN, "data.txt") || die "Can't open data.txt";

実行結果は次のようになります。

Can't open data.txt at flow5.pl line 1.

Copyright (C) 2002 杜甫々