外部の Perl スクリプトを実行する
do
は、後ろにブロックが続く (do BLOCK
) のか、
文字列が続く (do EXPR
) のかによって、その役割は大きく異なります。
do
の後ろにブロックが続く場合、その do
は関数ではありません。
ブロックの中にはコマンドをいくつか入れることができますが、
do
は、最後のコマンドの実行結果を返します。
次の例は 0 ~ 99 の間のランダムな整数を抽出し、それが 3 の倍数なら 1 を、
そうでなければ 0 を返します。
my $result = do {
my $num = int( rand(100) ); # 0 ~ 99 の整数のどれか
( $num % 3 ) ? 0 : 1; # 3 の倍数なら 1
};
print $result, "\n"; # 0 または 1
この構文の使いどころとしては、if
の条件式などが挙げられます。
1 行では無理だけれども数行なら何とかなる、といった状況で便利かもしれません。
if (
do {
my $num = int( rand(100) ); # 0 ~ 99 の整数のどれか
( $num % 3 ) ? 0 : 1; # 3 の倍数なら 1
}
)
{
print "Bingo!\n";
}
else {
print "Sorry.\n";
}
do BLOCK
構文は、while
や until
のループと組み合わせて使うこともできます。
この場合、BLOCK
の部分はループの条件式が評価される前に 1 度実行されます。
つまり、本来 while
なら一度も実行されなかったはずであっても、do-while 構文なら
1 度は必ず実行されることになります。
次のコードは while
によるループですが、変数 $num
の初期値が条件を満たさないため、ブロックは一度も実行されません。
my $num = 0;
while ( $num > 0 && $num < 5 ) {
print $num, "\n"; # このブロックは一度も実行されない
$num++;
}
一方、次の do-while
によるループは、変数 $num
の初期値は条件を満たさないものの、その条件を評価する前に 1 度ブロックを実行するため、
以降、ループが継続します。
my $num = 0;
do {
print $num, "\n";
$num++;
} while ( $num > 0 && $num < 5 );
なお、冒頭で解説した while
や until
の組み合わせではない
do BLOCK
構文は、ループとして考慮されません。そのため、
next
, last
,
redo
といったループ制御文は機能しませんので注意してください。
また、do BLOCK
は関数ではありませんので、
ブロックの中で return
を使うことはできません。
do EXPR
構文は、EXPR に Perl
スクリプトのファイル名(ファイルパス)を指定することで、そのスクリプトを実行してくれます。
do './stat.pl';
この do BLOCK
構文は、実質的に次のコードと同じです。
eval `cat stat.pl`;
EXPR が /
や .
で始まらなければ、
@INC から指定のスクリプトファイルを検索します。
use lib '.'; # @INC にカレントディレクトリを追加
do 'stat.pl';
do
は引数の Perl スクリプトの実行が成功すれば、そのスクリプトの最後の行の実行結果を返します。
./stat.pl
の最後が次のようなコードだったとしましょう。
my @ary = (1, 2, 3);
scalar @ary;
このとき、do
で ./stat.pl
を実行すると、
do
は 3
を返します。
my $res = do './stat.pl';
print $res, "\n"; # 3
do
が Perl スクリプトの実行に失敗すれば、
do
は undef
を返します。
Perl スクリプトファイルが見つからなかった場合、失敗理由は $! にセットされます。
一方で、Perl スクリプトは見つかったものの、Perl スクリプトの実行でエラーが出たのであれば、
$@ にその理由がセットされます。
いずれにせよ、do
はそのような状況に陥っても例外を投げません。
そのため、すべてのエラーを捕捉したいなら、まず $@ を評価し、その後、$!
を評価するようにしてください。
do './stat.pl';
if ($@) {
print "Failed to run the script: " . $@;
}
elsif ($!) {
print "The script was not found: " . $!;
}