• ベストアンサー

同じ関数を複数回呼び出し時のSTDERRの分岐命令について

お世話になります。 タイトルにあります通りなんですが、 ある状況下で同じ関数を順に複数回呼び出す際、エラーになった場合にどこの関数呼び出しでエラーが 起きたのかを知りたいと思い、下記のような形でテストしております。 my($file_name1,$file_name2,$file_name3); &Aaaaa(\$file_name1); &Aaaaa(\$file_name2); &Aaaaa(\$file_name3); sub Aaaaa{ my($file_name_ref) = @_; { $| = 1; if(STDERR){ print "ER:$$file_name_ref<br>\n"; open(STDERR, ">&STDOUT"); }else{ print "OK:$$file_name_ref<br>\n"; } } print "ここにデリファレンスして行いたい条件式を記述します"; } やりたい事は、リファレンスを使って呼び出した関数内で 関数が受け取ったリファレンスをデリファレンスして処理を行わせる際に、エラーorOKをその都度知りたいのです。 ※エラーの場合、どこの部分の関数を実行した時かを知りたいのです。 上記を実行した場合、エラーで Bareword "STDERR" not allowed while "strict subs" in use at test.cgi line 123. Execution of test.cgi aborted due to compilation errors. となってしまうのですが、これはif (STDERR)の部分をうまく指定できてないように思うのですが、解決方法をご教授願えませんでしょうか。 またこのようなケースの場合に一般的な良い事例などご存知でしたらあわせてご教授頂けますと幸いです。 またopen(STDERR, ">&STDOUT"); した後、close(STDERR);する場所はこのようなケースの場合どこが適切なのでしょうか。 お手数おかけしますが宜しくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.1

> if (STDERR) これで何を判定させようとしてるかが解らなかったので、外してるかもしれませんが、サブルーチンがどこから呼び出されたかを知りたいのなら、callerが使えます。こんな感じ: use strict; sub inv { my( $d ) = @_; eval { my $a = 1 / $d; }; die( $@, '['.join( ':', caller ).']' ) if $@; } eval { &inv( 1 ); &inv( 0 ); &inv( 2 ); }; print '<pre>Erro: ', $@, '</pre>' if $@; くわしくは、perldoc -f callerをご覧下さい。

taku0
質問者

お礼

> if (STDERR) についてですが、もしSTDERRだった場合、受け取ったリファレンスをデリファレンスしてどこの関数でエラーになるのかを$$file_name_refから知りたかったのです。 で、ご教授頂いたサンプルスクリプトを元にcaller を調べたのですが、 使い方について自分で思ったようにカスタマイズ表示させる事が困難でしたので、caller関係での解決策は見送りになってしまいました。 で、 複数の関数をeval{};で囲み呼び出す関数先の実行部分もeval{};で囲み print '<pre>Erro: ', $@, '</pre>' if $@; 部分にエラーが表示されるのは良かったのですが、その際デリファレンスしたい$$file_name_refをエラーメッセージに含ませるやり方がどうしてもわからず、結果的に下記のようにする事で解決としました。 sub Aaaaa{ my($file_name_ref) = @_; { # $SIG{__WARN__} = sub{ print STDERR "ERR1:$$file_name_ref ", @_; }; $SIG{__DIE__} = sub{ print STDERR "ERR2:$$file_name_ref ", @_; exit 1}; } print "ここにデリファレンスして行いたい条件式を記述します"; } ※参考にしたページ http://www.kt.rim.or.jp/~kbk/perl-5.8/perlfaq8.html#how_do_i_tell_the_difference_between_errors_from_the_shell_and_perl http://72.14.203.104/search?q=cache:_9m7xDcHj-8J:oshiete1.goo.ne.jp/kotaeru.php3%3Fq%3D979508+%24SIG%7B__DIE__%7D&hl=ja&gl=jp&ct=clnk&cd=3 この度はとても参考になる貴重なアドバイスを頂きまして色々と勉強になりました。 本当に有難うございました。

その他の回答 (1)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

>上記を実行した場合、エラーで…となってしまう use strict 指定下でSTDERR を変な使い方をしているからですね。 この場合、コンパイルエラーであって実行時エラーではないですから、 ソースを変更する必要があります。 このソースでやりたいことを私が勘違いしているかもしれませんが、 STDERR は、エラー出力ハンドラであって、エラーが発生したことを調べるためには使えません。 このようなエラーが起こりうるコードでエラーが起こったことを捕まえるには、一般的にはeval コードブロックで実行することで、エラーが起こった場合に処理を継続することができます。 例えば、次のように書きます。 sub Aaaaa{ my($file_name_ref) = @_; eval { #エラーを起こしそうなコードをeval ブロックで囲む print "ここにデリファレンスして行いたい条件式を記述します\n"; }; if($@){ #エラーメッセージが設定された! print STDOUT "$$file_name_refの処理中にエラーが発生しました\n"; print STDOUT "$@\n"; #エラーメッセージをSTDOUT に表示 } }

taku0
質問者

お礼

>STDERR は、エラー出力ハンドラであって、エラーが発生したことを調べるためには使えません。 そうなんですか。大変勉強になります。 で、ご掲示頂いたサンプルスクリプトを元に色々テストしてみたのですが Aaaaaサブルーチン内で if($@){ #エラーメッセージが設定された! print STDOUT "$$file_name_refの処理中にエラーが発生しました\n"; print STDOUT "$@\n"; #エラーメッセージをSTDOUT に表示} としましても、思ったようにすんなりいきませんで、色々とやってみたのですがどうにもしっくりこなく、結果的には下記のHPを参考にエラー箇所を把握する事ができましたので解決と致しました。 ですが、いつも大変貴重なアドバイス有難うございます。 ※参考にしたHP http://www.kt.rim.or.jp/~kbk/perl-5.8/perlfaq8.html#how_do_i_tell_the_difference_between_errors_from_the_shell_and_perl http://72.14.203.104/search?q=cache:_9m7xDcHj-8J:oshiete1.goo.ne.jp/kotaeru.php3%3Fq%3D979508+%24SIG%7B__DIE__%7D&hl=ja&gl=jp&ct=clnk&cd=3 ■解決した記述 sub Aaaaa{ my($file_name_ref) = @_; { # $SIG{__WARN__} = sub{ print STDERR "ERR1:$$file_name_ref ", @_; }; $SIG{__DIE__} = sub{ print STDERR "ERR2:$$file_name_ref ", @_; exit 1}; } print "ここにデリファレンスして行いたい条件式を記述します"; }

関連するQ&A