💎

Perl: eval 中の die と exit の挙動

2024/07/21に公開

要約

eval の中では die を基本的に使う。
exit だと eval でエラーをトラップ出来ない。

概要

Perl の (eval 中の) die, exit の挙動について確認したので書き残しておく。
きっかけは、以下のようなコマンドロガーがあり、一部のコマンドのログが吐き出されていないことがあったため。

# こんなかんじのコマンドロガーみたいなの

eval { $result = command(); };  # コマンド実行

if ( $result ) {
    print("result is $result\n");  # 成功していたら結果表示
} else {
    print("some error is occured: $@\n")
    # slack 通知とか
}

挙動を確認

die の場合

以下のような die するサブルーチンを用意して、eval の中で呼び出してやる。

sub command_die {
    print("command with die\n");
    die("failed command_die");
}

print("start\n");
eval { $result = command_die(); };

if ( $result ) {
    print("result is $result");
} else {
    print("some error is occured");
    print("error log: $@");
}

print("end\n");

結果は以下。eval でエラーをトラップして処理できている 👍

start
command with die
some error is occurederror log: failed command1 at main.pl line 8.
end

exit の場合

次は exit するサブルーチンを用意して呼び出してみる。

sub command_exit {
    print("command with exit\n");
    exit;
}

print("start\n");
eval { $result = command_exit(); };

if ( $result ) {
    print("result is $result");
} else {
    print("some error is occured");
    print("error log: $@");
}

print("end\n");

結果は以下。eval 以降の log が出ていないので、exit 以降が実行されていない 😭

start
command with exit

まとめ

エラーをトラップしたいサブルーチン中では die を使う。
eval の中で die を使うとエラーをトラップできるのに対して、exit だとその時点でプログラムが終了してしまう。

perldoc にも以下のように明記してあった 💦
https://perldoc.perl.org/functions/exit

Don't use exit to abort a subroutine if there's any chance that someone might want to trap whatever error happened. Use die instead, which can be trapped by an eval.

でもきっかけのケースだと、ログの処理部分が違うファイルに切り出してあったので、ちゃんと意識しないと書いている部分が eval 中で実行されるのを忘れちゃうようなと思ったり...

Discussion