- ベストアンサー
printが使えない?初心者が困っています
- 初心者がTemplate-Toolkitを使った関係でprintが使えなくなる可能性はあるのか?質問しています。
- Perlのプログラムで、サブルーチン内でprintを使用したいと思っていますが、うまくいきません。
- クラスの考え方を理解し始めた初心者が、printの使い方についてアドバイスを求めています。
- みんなの回答 (10)
- 専門家の回答
質問者が選んだベストアンサー
・なんでそこで eval するんでしょうか。 ・print で表示するっていうのは、CGI 機構を使って Web ブラウザーに対してですよね? HTTP ヘッダーを出さないと CGI は出力されないので、1回目と2回目で結果が変わることもあると思います。 ・普通はこういうとき warn を使ってエラーログを確認します。warn を使っても結果は一緒ですか? >知識がなく、まともな質問ができないのが悔しいです。 確かにおっしゃるとおりですね。であれば勉強すればいいと思います。 自分に関してもいえますが、Web の掲示板を使って質問を投げるのはカンタンにできますから飛びつきがちなんですが、自分の質問を要領よく要約してツボをついた質問をするわけですから結構な技術力がいります。 「謎のプログラムが裏で動いているかも」とかいいながら、会社の業務のプログラムを適当にいじっておかしいとか言ってるの怖くないですか。ぼくだったら怖いです。土曜も、日曜も出勤ですよね。brosis さんの体も心配です。 遠回りですが、本なりなんなりで基本を勉強してから、ご自分の力で問題を解決するか、技術力があって brosis さんを指導することで報酬が得られる方のご指導を仰ぐのがスジだと思います。 少なくともぼくはもう自分の限られた能力の限界を感じますから、これにて手を引かせていただきます。お役に立てず申し訳ありませんでした。
その他の回答 (9)
- TYWalker
- ベストアンサー率42% (281/661)
ひとつ前の回答で上げた豆プログラムの $m と同じ状態ですね。 グローバル変数をサブルーチンの中で変えたのに、サブルーチンの実行後値がリセットされることはありえません。 my $n; print $n; # 何も表示されない($n は undef だから。警告が起こる) &foo(); print $n; # 3 と表示される sub foo { $n = 3; }
お礼
ありがとうございます。 本日、初めてのサーバーへのアクセスにおいて、 my $n; sub subroutin_2 { # for ( $n = 0; $n < 2; $n ++ ) { # eval "print $n"; } の、eval "print $n"; が表示されました。しかし、すぐさま2回目のアクセスで、eval "print $n"; は表示されなくなりました。 この不思議(?)なサーバーの動きは、何か裏で他のプログラムでも動いているかの様です。 知識がなく、まともな質問ができないのが悔しいです。
- TYWalker
- ベストアンサー率42% (281/661)
さっきな subroutin_2 の中の for でも $n が my 宣言されてましたけど、どっちが正しいんですか? my $n; subroutine_2 { for (my $n... この2つの $n が赤の他人であることは分かりますよね? $n にスコープ(有効範囲)があるから。 #! /bin/perl my $n = 'global'; my $m = 'global2'; warn "1: $n"; warn "2: $m"; &foo(); warn "6: $n"; warn "7: $m"; sub foo { my $n = 'sub'; warn "3: $n"; warn "4: $m"; for my $n (1..3) { warn "5: $n"; } warn "6: $n"; } を実行すると、 C:\Documents and Settings\you\デスクトップ\foo>foo.pl 1: global at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 6. 2: global2 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 7. 3: sub at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 16. 4: global2 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 17. 5: 1 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 19. 5: 2 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 19. 5: 3 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 19. 6: sub at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 21. 6: global at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 11. 7: global2 at C:\Documents and Settings\you\デスクトップ\foo\foo.pl line 12. となります、と書けば回答になるでしょうか。
お礼
>この2つの $n が赤の他人であることは分かりますよね? 分かります。 sub subroutin_2 { の中で、print が効かないということで、 my $n; for ( $n=0; $n < 2; $n ++ ) { をあきらめ、変更して、 my $n; sub subroutin_2 { と、することにしました。すみません説明が抜けていました。 今、引っかかっているのは、$n が subroutin_2 のスコープを抜けると値がリセットされるのでは?ないかと思っています。 「そんなことは有り得ない。」ならはっきりと否定して頂けたら有難いです。
- TYWalker
- ベストアンサー率42% (281/661)
ああ、GET メソッドでパラメーターを受けているということは、CGI をブラウザーから起動しているんですね。 状況がわかりました。 Template-toolkit というものは HTML を組み立てるものらしいですね。 その時点で気づくべきでしたね。 まとめると、 (1) CGI で Perl のスクリプトを起動している (2) HTML は Template-toolkit を使って組み立てている (3) データに不整合があるので、デバッグしている (4) プログラムの途中に print を挟んで中間データを確認したい (5) しかし、print の結果が((2) で Template-toolkit を使って組み立てた HTML を表示している、そのブラウザー画面に)表示されない (6) しかしながら、Template-toolkit の使用をやめると、print が起動する (7) そこで、Template-toolkit が干渉して print を使用不可にしているという怪奇現象があるようなので、OKWave に相談した という状況ですね。 Template-toolkit は HTML のテンプレート(枠組み)を生成し、その中に変動するデータを差し込んで美しく整形して出力してくれるものですね。 よって、Template-toolkit を使って HTML を表示する前に何か print で出力しても、Template-toolkit が HTML を表示するときに表示をクリアーしてしまうので、消えてしまうんですね。 ところが、Template-toolkit の使用を切れば、表示がクリアーされないので、print 出力が生きるということですね。 ということで、brosis さんのおっしゃる Template-toolkit が干渉して print の出力が消えてしまうと言うのは、ある意味当たっているんですね。 また、前のお礼にあった、 print qq#Expires: Mon, 26 Jul 1997 05:00:00 GMT\n#; print qq#Cache-Control: no-store, no-cache, must-revalidate\n#; print qq#Cache-Control: post-check=0, pre-check=0\n#; print qq#Pragma: no-cache\n#; print qq#Content-Type: text/html; charset=UTF-8\n#; printf qq#Content-Length: %d\n\n#, length $buffer; というのは HTTP ヘッダーですね。 これを出力するときに、それまでの print がクリアされているんですね。 よって、brosis さんのおっしゃるこれらの print が、デバッグ用の print をクリアーしてしまったというのもある意味当たっているんですね。 どうも、いい加減に見ていてすみませんでした。 で、以上の状況を踏まえて、プログラム中にデバッグのために中間データを出力するにはどうすればいいか。 以下のような手段が考えられます。 1. print の代わりに warn を使う。 データは HTTP サーバー(Apache か何かが動いていると思います。要は Web サーバーのこと)のエラー ログ(UNIX だとすれば、/var/log/error.log かなにか、Apache の設定によって異なる)を見ればよい。 そのまま表示するには % tail /var/log/error.log を使う。(tail コマンドは長大なテキストファイルの末尾のみを表示する) あるいは、warn で warn "brosis-debug: n", $n; のように常に brosis-debug: などとヘッダーをつけておけば、 % grep "brosis-debug:" /var/log/error.log とすれば brosis-debug: というヘッダーのついたログのみが表示されます。 2. HTML-toolkit でテンプレートを定義しているところに手を入れ、デバッグのために表示をしたい中間データ($n とか $result とか)を表示するエリアを作り、他のデータ同様そこに値を差し込む 3. 標準出力(ブラウザー画面)ではなく、何らかのデータ ファイルに print させる。 ただし CGI スクリプトは nobody というユーザーによって実行されるので、そいつに書き込み可能なディレクトリを作って書き込む必要があるから注意 4. sendmail コマンドを使って中間データを自分にメールさせる これ以前やったことがあります。 以上です。答になっていればいいがと思います。 なんかかえって時間をとらせてしまってすみませんでした。
お礼
ご回答ありがとうございます。 >どうも、いい加減に見ていてすみませんでした。 とんでもないです。 現在は、Template-toolkitのスクリプトをすっ飛ばしていますので、 printが使える状況です。 ただ引っかかるのが、サブルーチンの中でprint や warn が効かないことです。 例えば、 my $n; sub subroutin_2 { # for ( $n = 0; $n < 2; $n ++ ) { # } print $n, "<br />"; print "AAA"; my $result = []; # $result にデータを代入する作業 # return $result; } print "BBB"; print $n; の print $n, "<br />"; や print "AAA"; が表示されないのです。 print "BBB"; は表示されます。 しかし、サブルーチン外の print $n; は表示されません。 サブルーチン内で print するのは、とりあえず置いといて、 サブルーチン外での print $n; の不表示は、 全く my $n; から値が代入されてないということになりすね。 しかし、 sub subroutin_2 は働いてはいるのです。 今、sub subroutin_3 { というものがあり、 my $prames; sub subroutin_3 { # my $ret = subroutin_2; # $params = { result => $ret, # # }; return $params; } print Data::Dumper-Dump( [$params] ); で、不整合な結果のデータですけど表示はされるのですから。 となると、print $n; で値が入ってないということは、 subroutin_2 内から外へのスコープの間に、$n の値をリセットしてしまう原因があるということですね。 こうなるとクラスとかオブジェクトの作り方の問題になるのでしょうか?
- TYWalker
- ベストアンサー率42% (281/661)
また連投ですみません。 print してみているのはデバッグのため(プログラムの動きを調べるため)ですよね? であれば print の変わりに warn を試すのも手だと思います。
- TYWalker
- ベストアンサー率42% (281/661)
なるほど、他の人が書いたプログラムの修正を負かされているんですね。 事情がわかりました。 失礼しました。 しかしながら、アドバイスは変わりません。 (1) use strict; use warnings; をつけてください。 (2) 最小の(動作する)プログラムを組んで、1個1個の機能を実験してください。 少なくともbrosisさんが抜き出した部分だけでは不具合の原因はわかりません。 あと、brosisさんが推測した原因(use Template; がメインルーチンやサブルーチンの print に干渉する)もありそうではないと思います。 あと、eval を介してのサブルーチン呼び出しが前からなら、前のプログラムの書き方もちょっとナゾです。 納期が決められていて、OKWave 以外に(もともとプログラムを書いた人や、会社の先輩などに)アドバイスが求められないなら、その体制もちょっと疑問です。 いやいや、無理な仕事を任されて困ることは誰でもあるものです。 苦しみを乗り越えたら強くなります。 がんばってください。
お礼
TYWalkerさん、アドバイスと激励ありがとうございます。 eval { subroutin_1() }; について説明していませんでした。 このコードは実際には、 my $action = sprintf '%s', $this->{page}; eval { $this->$action() }; です。 前のページから送られるGETクエリによって使うサブルーチンが変わります。(表示されるものが変わります。今回の件は、subroutin_1から使い始めます。) use strict; use warnings; についても大丈夫です。元々記述されておりました。すみません。
- TYWalker
- ベストアンサー率42% (281/661)
連投ですみません。 pm ファイルでなく、ファイルの中にメインとクラスが両方あるんですね、失礼しました。 で、メインで呼び出してるのは execute で、呼び出されてるのは excute ですけど(つづり間違いがありますけど)大丈夫ですか? で、excute の中で subroutin_1 を eval してるわけですけど、これ単純に呼び出さないで eval している理由はなぜですか?(eval でも動くようですけど・・・) subroutin_1 の中で sunroutin_2 を呼び出してますけど(つづり間違いがありますけど)大丈夫ですか? 昨日も言いましたが、 use strict; use warnings; を書いて、すべてのエラーと警告をつぶしてみましたか? brosis さんはたしかにかなりの初心者のようなので、長い難しいプログラムを書いてその一部分だけを書いて質問するというのはチョット無理だと思います。 もっとプログラムをギリギリ短くして、おかしいと思う現象が起こる最短のプログラムを作って、そのプログラムの全文と、警告、エラーを出してくれたら相談にのれると思います。 (一般にたとえ上級者であっても、質問に使うプログラムはギリギリ最小に書くものです)
お礼
ご回答ありがとうございます。 スペルミスは、OKwaveでのみです。すみません。 実は、エラーが出でいるわけではないのです。 こんな初心者に対して、長いソースコードによるデータ取得の不具合の修正が任されているのです。
- TYWalker
- ベストアンサー率42% (281/661)
#1 を書いたものです。 Template モジュールなるものでやっているのは、単なるまた別の print なので、それがユーザーサブルーチンの print に 影響を与えることはないと思います。 print "string"; というのは、実際にはそのときのデフォルトのファイルハンドルへの出力で、デフォルトのファイルハンドルは select FILEHANDLE; などのように別のファイルハンドルに設定されるまでは STDOUT というものになっています。もし別のファイルハンドルにデフォルトが変わっていたとしても print STDOUT "string"; のように明示的にファイルハンドルを書いてやればちゃんと標準出力に表示されるはずですのでためしてみてください。 あと、もし use Template; が疑わしいのなら、上のサブルーチンは特にそれに関係ないようなので一時的にそれを外してみればいいんじゃないでしょうか。 あと、本当に subroutin_2 は呼ばれてるんでしょうか。 上のコードは pm ファイルで、それを use するメインは別にあるんですよね? ・Template-Toolkit を使う ・pm ファイルを使う ・サブルーチンの仲で print を行う という問題がごっちゃになっていて、どこに問題があるのかわからなくなっていますね? であれば、急に難しいことをせずに、1個1個解決していくほうがいいと思いますよ。
- genkivogue
- ベストアンサー率22% (4/18)
for ( my $n = 0; $n < 2; $n ++ ) { でどうですか。 $n の スコープが for ループの外になってるのではと思います。 use strict; すると、その辺は指摘してもらえるかと。
お礼
ご回答ありがとうございます。 あえて my $n; for ( $n = 0; $n < 2; $n ++ ) { こうしてます。 for文の外で、print $n; をしてちゃんと2回ループされているか確かめるためです。
- TYWalker
- ベストアンサー率42% (281/661)
どこに print 書きました? my で作った変数はスコープが切れるとなくなりますよ。 具体的に言うと、 for ( my $n = 0; $n < 2; $n ++ ) { # } の $n は for ループの外に出ると消えちゃうし、 sub subroutin_2 { # for ( my $n = 0; $n < 2; $n ++ ) { # } my $result = []; # $result にデータを代入する作業 # return $result; } の $result は subroutin_2 が終わると消えちゃいますよ。 プログラムは最初に(#! /usr/bin/perl のすぐ下に) use strict; use warnings; とかくと、いろいろ変なところがあると怒られるので便利です。
お礼
回答ありがとうございます。 for ( my $n = 0; $n < 2; $n ++ ) { を my $n; for ( $n = 0; $n < 2; $n ++ ) { にして subroutin_2内で print $n; しても表示されませんでした。 おそらくTemplateモジュールを使っているところで、 print qq#Expires: Mon, 26 Jul 1997 05:00:00 GMT\n#; print qq#Cache-Control: no-store, no-cache, must-revalidate\n#; print qq#Cache-Control: post-check=0, pre-check=0\n#; print qq#Pragma: no-cache\n#; print qq#Content-Type: text/html; charset=UTF-8\n#; printf qq#Content-Length: %d\n\n#, length $buffer; print $buffer; などとやっている関係でしょうか? この際、use Template; をやめちゃてます。 デバッグの作業を行う為です。 今は、 my $result; sub subroutin_2 { # # } みたいことをやってます。 本来は subroutin_2 内でprint Data::Dumper->( [$result] ); とか print $n; やりたいのですが。。 できますよねぇ?subroutin_2 内で。
お礼
eval "print $n"; したのは特に意図はありませんでした。 ずっと残しておいたコードが、たまたま今日初めてのCGIアクセスで効いた、それだけです。 >・print で表示するっていうのは、CGI 機構を使って Web ブラウザーに対してですよね? はい、そうです。 2回目のアクセス以降は、一切 print $n; も eval "print $n"; も subroutin_2 の中で効かなくなりました。 >「謎のプログラムが裏で動いているかも」とかいいながら、会社の業務のプログラムを適当にいじっておかしいとか言ってるの怖くないですか。 怖いとか、あまり深く考えていませんでした。ソースのバックアップとっているから大丈夫。。だろうと。 >遠回りですが、本なりなんなりで基本を勉強してから、ご自分の力で問題を解決するか、技術力があって brosis さんを指導することで報酬が得られる方のご指導を仰ぐのがスジだと思います。 そうですね。上長に相談します。 こんなにシツコク、分かりにくい質問で申し訳ございませんでした。 長い間お付き合い頂きまして、ありがとうございました。