関数内で同じ事を繰り返すと、2回目の値が1回目のコピーになってしまう事について

このQ&Aのポイント
  • 関数内で同じ処理を繰り返すと、2回目の値が1回目のコピーになる現象が起こります。
  • この現象は、変数のスコープの問題によるものです。
  • 関数内で変数を使う場合、その変数のスコープを明示的に指定する必要があります。
回答を見る
  • ベストアンサー

関数内で同じ事を繰り返すと、2回目の値が1回目のコピーになってしまう事について

sub Test { #■hoge1内の情報を参照 opendir(DIR, "/home/hoge1/data/"); @list = sort{$a <=> $b} grep(/\d$/, readdir DIR); closedir(DIR); foreach $_ (@list) { #hoge1...test/ require "/home/hoge1/data/$_/$_.log";#中身は右記のような形で1行です。$pass = '1234'; $Name = 'あああ';1; require "/home/hoge1/data/$_/no.dat";#中身は右記の1行です。$No = '18';1; print "$Name,$No\n"; } #■hoge2内の情報を参照 opendir(DIR2, "/home/hoge2/data/"); @listA = sort{$a <=> $b} grep(/\d$/, readdir DIR2); closedir(DIR2); foreach $_ (@listA) { require "/home/hoge2/data/$_/$_.log";#中身は右記のような形で1行です。$pass = 'aaaa'; $Name = 'いいい';1; require "/home/hoge2/data/$_/no.dat";#中身は右記の1行です。$No = '18';1; print "$Name,$No\n"; } } Test関数を呼び出し上記の状態を実行しますと、hoge2(仮に5つのリスト)の各$Nameと$Noをprintした際、 hoge1の最後に実行した値がhoge2の5つ全てにコピー表示されてしまう現象になってしまいます。 行なってみた事は、 #■hoge2の所で undef$Name; undef$No; としたり、 関数の頭で my$Name; my$No; としてみたり、またhoge1とhoge2を別の関数に分け、 sub TTest1{ &Test1(); } sub TTest2{ &Test2(); } として、個別に呼び出してみたり、下記のように sub Test{ &Test1(); &Test2(); } 同時に呼び出してみたりしたのですが、思うように表示されずここ数日はまってしまっています。 これを回避するにはどのようにすれば良いかご教授頂けませんでしょうか。 またこの現象は何故起こるのかもご説明願えましたら幸いです。 本来、aaaa<>いいい<>というデータ構造にしておけば、このような問題にならないような気がするのですが、 作ってしまったので、どうにか保存形式を変えずにデータを取り出せればと思っています。 お手数お掛けしますが宜しくお願いしたします。

  • taku0
  • お礼率80% (160/199)
  • Perl
  • 回答数1
  • ありがとう数1

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

  • ベストアンサー
回答No.1

??? どのような環境でしょう。 Windows XP ActivePerl v5.8.8 built for MSWin32-x86-multi-thread の環境で実行しましたが、質問の現象を再現できませんでした。 下記コードを実行した結果です(リストは3つずつ)。 --- start --- $#list=2 @list=1 2 3 あああ,18(pass=1234) いいい,28(pass=2234) ううう,38(pass=3234) $#listA=2 @listA=21 22 23 かかか,218(pass=21234) ききき,228(pass=22234) くくく,238(pass=23234) --- end --- ========================================================================== print "--- start ---\n"; &Test(); print "--- end ---\n"; sub Test { #■hoge1内の情報を参照 opendir(DIR, "/tmp/hoge1/data/"); @list = sort{$a <=> $b} grep(/\d$/, readdir DIR); closedir(DIR); print "\$\#list=$#list\n"; print "\@list=@list\n"; foreach $_ (@list) { #hoge1...test/ require "/tmp/hoge1/data/$_/$_.log";#中身は右記のような形で1行です。$pass = '1234'; $Name = 'あああ';1; require "/tmp/hoge1/data/$_/no.dat";#中身は右記の1行です。$No = '18';1; print "$Name,$No(pass=$pass)\n"; } print "\n"; #■hoge2内の情報を参照 opendir(DIR2, "/tmp/hoge2/data/"); @listA = sort{$a <=> $b} grep(/\d$/, readdir DIR2); closedir(DIR2); print "\$\#listA=$#listA\n"; print "\@listA=@listA\n"; foreach $_ (@listA) { require "/tmp/hoge2/data/$_/$_.log";#中身は右記のような形で1行です。$pass = 'aaaa'; $Name = 'いいい';1; require "/tmp/hoge2/data/$_/no.dat";#中身は右記の1行です。$No = '18';1; print "$Name,$No(pass=$pass)\n"; } }

taku0
質問者

お礼

解決しました。 質問する際、色々な前提条件を取り払い簡単かつポイントを絞りhoge1とhoge2という形に置き換えて質問させてもらってたのですが、原因はスクリプト内で質問内容でいうと双方ともhoge1を読み込んでいた為でした。 具体的には、下記のように出力先を2箇所という形にしており sub Test{ #■処理1 if($a eq 'a'){ open(OUT,">/tmp/hoge2/data/a.txt"); }else{ open(OUT,">/tmp/hoge2/data/x.txt"); } if($a eq 'a'){ #ここに質問内容 }else{ #同様にここにも質問内容 } #■処理2 if($a eq 'a'){ open(OUT,">/tmp/hoge2/data/b.txt"); }else{ open(OUT,">/tmp/hoge2/data/y.txt"); } if($a eq 'a'){ #ここに質問内容 }else{ #同様にここにも質問内容 } } 上記のですと処理1と処理2共$a eq 'a'の場合は同じ所を読み込むようになり、 今回のようなケースに陥ってしっていたようです。 で、読み込み元を別にすれば出力時には質問内容のようなエラーにはならない事も確認でき、原因がわかったので出力先を2箇所にする事も何とか解決できそうです。 有難うございました。

関連するQ&A

  • cshのsed

    ヤマトです。 cshのsedについて質問します。 環境はRed Had Linux7.2です。 文字列置換でsedを使っています。 置換文字列に'/'が入ってしまう場合正常に動作しません。 原因は分かります。'/'が多いって事ですよね(曖昧な言い方ですみません) どのようにしたら、できるでしょうか? 以下に、サンプルを書きます。 ====SAMPLE.sh(一部抜粋)==== set DATA_DIR = /home/hoge set FILE_NAME = hoge.txt sed "s/__DIR__/$DATA_DIR/g" < FILE_NAME > FILE_NAME.sed ====hoge.txt==== 置換した ディレクトリは __DIR__/です ====hoge.txt.sed(作成したいファイル)==== 置換した ディレクトリは /home/hoge/です どのようにsedしたら良いのでしょうか? 教えて頂けると有り難く思います。宜しくお願いします。

  • Perlで use strict して our変数

    Perl 初心者です。初めて質問します。 test_sub.pl で宣言した変数を test_main.pl から参照したくて悩んでいます。 環境 : WindowsXP / ActivePerl 5.14.2 -------------------- * test_sub.pl -------------------- #!/usr/bin/perl use strict; our $hoge = 'HOGE'; 1; -------------------- * test_main.pl -------------------- #!/usr/bin/perl use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; -------------------- これを実行すると、 Global symbol "$hoge" requires explicit package name at C:/public_html/cgi-bin/test_main.pl line 7.\r というエラーが出ます。 require する前に、test_main.pl のほうで our($hoge); と宣言したり 参照する際に print $main::hoge; とパッケージを指定したりすればいけるのですが、 これらをしないとできないものなのでしょうか。 use strict; を書かなければ最初のソースでも動くのですが use strict は書きたい… 継承のようなことをしたいのです。 ちなみに以下試してみたソースです。 -------------------- * test_main.pl -------------------- #!/usr/bin/perl ######################################## # NG use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; ######################################## # OK our変数を宣言しておくといける =pod use strict; our ($hoge); require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $hoge; =cut ######################################## # OK 参照する際にパッケージ名を指定すればいける =pod use strict; require 'test_sub.pl'; print "Content-type: text/html\n\n"; print $main::hoge; =cut ######################################## ######################################## # NG =pod use strict; use base qw(test_sub); print "Content-type: text/html\n\n"; print $hoge; =cut ######################################## -------------------- * test_sub.pm -------------------- #!/usr/bin/perl package test_sub; use strict; our $hoge = 'HOGE'; 1; -------------------- NG パタンはどちらも Global symbol "$hoge" requires explicit package name のエラーとなります。 もしご存じの方がいらっしゃいましたら教えてください。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • 同一テーブル内で違うフィールドにデータをコピー

    ryomaniaと申します。 MySQL3.23.58を使用しています。 質問の内容なのですが、NO、CNO、NAMEというフィールドを持つテーブル顧客があります。 NOにはauto_incrementで連番の数字が自動で入ります。CNOにはNOと同じ数字を入れたいと思っています。但し最初は数字の0が入っています。NAMEには名前が入っています。 例: NO | CNO | NAME 1 | 0 | test1 2 | 0 | test2 3 | 0 | test3      ・      ・      ・ といった感じです。この状態からupdate構文などを使用して、もしCNOが0であればNOのデータをCNOにコピーするということは可能でしょうか?出来れば複数の行を一度に行いたいと思っています(1000~3000行くらい)。 googleなどで調べては見ましたが答えというかいいヒントが見つかりませんでした。 変な言い回しになっているかもしれませんがよろしくお願いします。

    • ベストアンサー
    • MySQL
  • 更新クエリでテーブルを書き換えたい

    データが0件のテーブルに、更新クエリで一つのレコードを追加したいのですが そもそもテーブルにデータが入ってない状態だから更新すらできないのですが こういう時どうすればいいでしょうか? Ttest01テーブルにaを入れたい場合、 UPDATE Ttest01 SET Ttest01.test01 = "a"; これだとうまくできません。 Ttest01のtest01フィールドの1行目にaを入れる方法を教えてください。

  • phpでランダムにページを表示

    001.html~999.htmlの内容をランダムにPHPを使用しページを 表示させたいのですが以下のソースでは01.html表示になり 困っています。 <?php $dir_name = "ads"; $ads = array(); $dh = opendir($dir_name); while ($data = readdir($dh)) { if (!is_dir($data)) { array_push($ads, $data); } } closedir($dh); shuffle($ads); include("$dir_name/$ads[0]"); ?> どのようにすれば001になるのでしょうか、 どなたかご教示お願い致しますm(_ _)m

    • ベストアンサー
    • PHP
  • ファイルの書き込み

    以下のことがしたいです。 testフォルダよりテキストファイル達を読み込み、 ある行だけ取り除いたのちnewtestフォルダに書き出したいと思います。 以下、コードになります。 #!/usr/bin/perl $n_dir = "newtest/"; $b_dir = "test/"; opendir(DIR, $b_dir); while($file = readdir(DIR)){ $nfile="$n_dir$file"; $bfile="$b_dir$file"; if (-T $bfile) { open(IN, $bfile); #testフォルダよりファイルの読み込み @list = <IN>; close(IN); open(OUT,">$nfile"); #newtestフォルダに書き出し while(@list = <IN>) { #testフォルダ内のファイルを一行ずつ読み込み if (@list =~ /test/) { #行にtestという文字列があるぎょうだけ書き出し print OUT @list; } } close(OUT); } else{next;} } closedir(DIR); ということをやりたいのですが、 書き出されるファイルは空です。 どこが間違っているのでしょうか。 エラーなどは特にありません。 testフォルダのファイル達が そのままnewtestフォルダに書き出されるのですが、 中身は空です。 ご協力お願いします。

    • ベストアンサー
    • Perl
  • ライブラリ関数について教えてください

    C言語を独学で勉強しています。 ファイルの中のデータと配列データが一致するかを調べるプログラムを作ろうとしています。 しかし、私が作っているプログラムでは表示結果が正しくありません。 char型では==を使って一致かどうかを調べることが出来ないので、ライブラリ関数を使う必要があることを知ったのですが、調べてもよくわかりませんでした・・・ どのように作ればいいのか詳しく教えていただけないでしょうか。 よろしくお願いします。 #include<stdio.h> struct test { char no[5]; char name[10]; char english[5]; char math[5]; }; int main(void){ FILE *fp; int i; char f_no[5], f_name[5]; struct test data[5] = { {"001","akemi","100","40"}, {"002","tadao","59","76"}, {"003","mika","94","69"}, {"004","hiroshi","54","98"}, {"005","kazu","39","57"} }; struct test *test_p; test_p = data; if ((fp = fopen("test.txt", "r")) == NULL) { printf("NOT OPEN FILE\n"); } else { while (fscanf(fp, "%s%s", f_no, f_name) == 2) { for(i = 0; i<=5; i++) { if((test_p->no == f_no) && (test_p->name == f_name)) { printf("%s %s 英語%s 数学%sです。\n", f_no, f_name, test_p->english, test_p->math); } else { printf("%s %s 一致しません\n", f_no, f_name); break; } ++test_p; } } } fclose(fp); }

  • QNo.4191217 ライブラリ関数について教えてくださいの質問をした者です。

    質問を連投するのは気が引けたのですが、 どうしても分からなかったのでまた質問させてください・・・ ファイルの中のデータと配列データが一致するかを調べるプログラムを作ろうとしています。 前質問で、ライブラリ関数について教えていただき 以下のようにプログラムを作成してみました。 しかし、これだと結果が何も出力されませんでした・・・ 何が間違っていて、どうすればいいのか詳しく教えていただけないでしょうか。 よろしくお願いします。 #include<stdio.h> struct test { char no[5]; char name[10]; char english[5]; char math[5]; }; int main(void){ FILE *fp; int i; char f_no[5], f_name[5]; struct test data[5] = { {"001","akemi","100","40"}, {"002","tadao","59","76"}, {"003","mika","94","69"}, {"004","hiroshi","54","98"}, {"005","kazu","39","57"} }; struct test *test_p; test_p = data; if ((fp = fopen("test.txt", "r")) == NULL) { printf("NOT OPEN FILE\n"); } else { while (fscanf(fp, "%s%s", f_no, f_name) == 2) { for(i = 0; i<=5; i++) { if((strcmp(test_p->no,f_no)==0) && (strcmp(test_p->name,f_name)==0) { printf("%s %s 英語%s 数学%sです。\n", f_no, f_name, test_p->english, test_p->math); } else { printf("%s %s 一致しません\n", f_no, f_name); break; } ++test_p; } } } fclose(fp); } test.txtの中身 001 akemi 002 kazuo 003 tadashi 005 mika 006 xxx

  • データを送るのと値を渡すのを同時に行いたい

    a hrefでデータを送るのと値を渡すのを同時に行いたいのですがどうすればいいのでしょうか。 下記のa hrefでのデータを送りに<a href="http://www.localhost/hoge.php?name=papa&age=30"> のような固定された値を受け渡したいのですがどのようにすてばいいのでしょうか <form name="form1" action="test" method="post"> <input type="hidden" name="str" value="aaa"> <A HREF="javaScript:form1.submit();">ここの書き方がわかりません</A> <form>

  • チェックボックスからの値を受け取る

    つたなくもperlを使ってCGIスクリプトを作っている者です。 <input type="checkbox" name="test" value="1">1 <input type="checkbox" name="test" value="2">2 <input type="checkbox" name="test" value="3">3 上記のように、nameは全て同じ名前にして、データを受け取りたいと思っています。 ただ、 if($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{CONTENT_LENGTH}); } require './jcode.pl'; @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # 文字コードをS-JIS変換 &jcode'convert(*value, "sjis", "", "z"); $data{$name} = "$value"; と、最初に$data{test}に格納をしています。 現在は全ての項目にチェックをいれても、 3 と表示されてしまいます。 なんとかjcode.lib以外のモジュールを使わないで、 $data{test}に選択された全ての項目を入れることはできないでしょうか。 ご教授いただけましたら幸いです。

    • ベストアンサー
    • Perl

専門家に質問してみよう