ルモーリン

エラー出力が出ない

投稿:2018-09-22、更新:2018-10-01

エラーメッセージが表示されないと対処のしようがないので、とても興味を覚えました。
これは無事に動作する最小限のコードです。 文字コードはutf8です。
#!/usr/bin/env perl -w

use utf8;

binmode STDERR, ":encoding(cp932)";

0 or die "無理で~す";
こういう風に表示されます。
無理で~す at sample_45.pl line 7.
実行しても全く表示されないコードです。 差は間違いさがしレベル。 文字コードも同じです。
#!/usr/bin/env perl -w

use utf8;

binmode STDERR, ":encoding(cp982)";

0 or die "無理で~す";
binmodeのencodingの中に指定する文字コード名を間違えてもbinmodeの実行は成功、 実際にエラー出力をする時点でエンコードできずに失敗、 そのエラーも出力できず、エラー出力が出ないと推測しました。
2018-10-01 元ネタのアカウントさんから連絡があり、私が症状を誤解していたので改めて挑戦しました。 アカウントさんの記事です。 週記くらい | Active Perl で binmode STDERR, “:encoding(cp932)”; 後の dieでフリーズ
メッセージが表示されず、実行中のまま、プロンプトが表示されない。
上記の記事と同様、私の環境でも再現しました。 それからフリーズする要素を絞り込んでいきますと、
binmode STDERR, ":encoding(cp932)";
の実行が肝になっているようです。 それとdieコマンドでPerlがエラーメッセージにスクリプトのファイル名(パス含む)を追加する際は、 文字コードがcp932のまま、右から左へ(無変換で)入れているようです。 元々がcp932なのにbinmodeの指定でutf8前提でcp932に変換してしまうケースでフリーズしていました。 なので、dieでなくてもbinmode実行後に実行時エラーが発生すればパスの漢字変換に失敗してフリーズしました。 それと$SIG{__DIE__}にハンドラを指定してdieに渡る前のメッセージを見ると、 dieに指定したメッセージとperlが追加したメッセージが連結されてしまうので、 連結前に文字コードを統一しなくてはなりません。
STDERRをbinmodeで変更しなければ発生しませんけれど、 dieにutf8のリテラルを指定すると、 まんまコマンドプロンプトに出力しようとして文字化けしてしまいます。
dieする際のメッセージをcp932にエンコードすればよいけれど、毎度やるのは面倒なので。
#!/usr/bin/env perl -w

use utf8;
use Encode::Locale;
use subs "die";

die "本日は晴天なり";

exit;

sub die {
 	my $msg = Encode::encode locale => $_[0];
 	my (undef, $filename, $line) = caller;
 	print STDERR "$msg at $filename line $line.\n";
 	exit;
}
  • STDERRにエンコードを指定しない
  • dieに指定するメッセージは出力コンソールに合った文字コードにエンコードしておく