• 締切済み

Perlのmyとourについて

myとourの違いが、飲み込めません。 以下、当方の環境とします。 【コード(1) ファイル名は read.pl とする】 #!/bin/perl use strict; use warnings; my @filelist = <abc*.log>; foreach my $i (0 .. $#filelist){ open(IN, "$filelist[$i]"); my @alltxt = <IN>; sub f_readlines { my $export=0; foreach my $strings(@alltxt){ $export .= $strings; } return $export; } 【コードの説明と前提】 これは、read.plを実行すると、同じディレクトリにある、「abcで始まり .logで終わるファイル」のすべてを引数として、 同じ処理を繰り返すコードです。 実行時のカレントディレクトリには、abc001.log、abc002.log、abc003.logという3つのファイルが存在します。 abc001.log には aaaaaaa という文字列が書き込まれています。 abc002.log には bbbbbbb という文字列が書き込まれています。 abc003.log には ccccccc という文字列が書き込まれています。 【コード(1)の実行結果】 $ ./read.pl aaaaaaa aaaaaaa aaaaaaa 【現状と当方の考え】 このコードの本来の目的は、存在するファイルの数だけ、その中身を順次読みだす、というものです。 ですので、コード(1)の実行結果は $ ./read.pl aaaaaaa bbbbbbb ccccccc になってくれないといけないのです。 しかし、 my @alltxt = <IN>; の行を our @alltxt = <IN>; に書き換えると、うまくいきました。 ネットを見ていると、myはスコープの範囲が限定的で、ローカルな変数のようで、 グローバル(どこでも変数として取り出せる)なものが our、というように読み取れます。 foreach の処理の中で宣言した my @alltxt ですから、 ファイルの数だけ、毎回 @alltxt の中身の値は変わるはずです。 それが、変わってくれず、初回に@alltxtに読み込んだ aaaaaaa だけが、ファイルの数だけ 出力されてしまいます。 【質問したいこと】 (1)myを使って代入した変数の中身は、同じスコープ内で作成した関数からは読みだせないのか? (2)それならば、なぜ初回のaaaaaaaは、読み出せているのか? 以上よろしくお願いします。

  • Perl
  • 回答数2
  • ありがとう数10

みんなの回答

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

あ, #1 は完全に勘違いしてた. ということで最初からやり直し. まず, my を使うと「そこを通るたびに違う変数を作る」と思っていい. つまり, 今の場合 foreach で回す 3つのファイルのそれぞれに対して @alltxt が存在する. それに対して, サブルーチン f_readlines は 1つだけ存在し, その中では「最初の @alltxt」だけがアクセスできる. その結果「初回に@alltxtに読み込んだ aaaaaaa だけが、ファイルの数だけ出力されてしまいます」という結果になっている (2つ目以降では「ファイルから読み込んだ値を保持する @alltxt」と「f_readlines からアクセスする @alltxt」が別個に存在する). 一方 our は「(必要ならグローバルな変数を作って) それを現在のスコープに導入する」という働きになる. だから my の代わりに our を使うと @alltxt は 1つだけ存在し, それをサブルーチン f_readlines がアクセスするので期待通りの動作になる. ちなみに勘違いのもとは, どうも foreach でまわす変数だけは扱いが違うっぽいところ.

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

Perl のサブルーチンは基本的にファイルスコープでしか作れない. だから, そのプログラムは #!/bin/perl use strict; use warnings; my @filelist = <abc*.log>; sub f_readlines { my $export=0; foreach my $strings(@alltxt){ $export .= $strings; } return $export; } foreach my $i (0 .. $#filelist){ open(IN, "$filelist[$i]"); my @alltxt = <IN>; # 以下の詳細は不明 と書いたのと同じことになる. というのが (1) の答え. (2) については完全なプログラムが提示されていないので不明.

関連するQ&A

  • shシェルでのファイル操作

    初心者です。 shシェルであるファイルの先頭行及び最終行を削除して別ファイル(新規)に書き出したいのですが、何か良い方法があれば教えてください。 (例) 元ファイル(AAA)の内容 1234567 aaaaaaa bbbbbbb ccccccc 7654321 削除後のファイル(BBB)の内容 aaaaaaa bbbbbbb ccccccc

  • excelで空白行を無視する方法

    excel2003について質問です。 「20090909aaa.xls」 aaaaaaa bbbbbbb ccccccc ******* 「20090909bbb.xls」 xxxxxxx yyyyyyy zzzzzzz ******* という内容で複数のxlsファイルがあったとします。 その複数ファイルを********を区切りに、 aaaaaaa bbbbbbb ccccccc xxxxxxx yyyyyyy zzzzzzz という風に並べたファイルを作りたいのですが、 cccccccの後にある空白行を無視する方法が分かりません。 値が入って入ればそれを表示して、無ければ次の行のセルを見て、 隙間無く表示するにはどういう風に書けばいいのでしょうか?

  • Excelファイルから住所宛名印刷をする方法

    Excelファイルから住所宛名印刷をするにはどうするのでしょうか? Excelファイルに沢山の宛名と氏名が記入されています。これを使って封筒に貼り付けられるように宛名印刷をしたいのですが、どうすればいいのか分かりません。 例)Excelファイル>>> 山田太郎 〒555-5555 東京都AAAAAAA 山田次郎 〒444-4444 横浜市BBBBBBB 山田花子 〒333-3333 大阪市CCCCCCC となっているのを宛名のフォーマットに合わせて _________________________ | | 〒555-5555 | 東京都AAAAAAA |   山田太郎  | _________________________ | | 〒444-4444 | 横浜市BBBBBBB |   山田次郎  |     : と自動的に変換して印刷したいのです。 ご存じの方、教えてください。

  • Oracle9iにて接続ホストを変更したい場合

    あるデータベース兼アプリサーバに接続しているクライアントより、 テスト環境用として構築した全く同じ環境の別サーバに接続させようと思い、 以下のtnsnames.oraの「(HOST= )」をテスト用サーバのホスト名に変更しましたが、「ORA-12535: TNS: 操作はタイムアウトしました。」が発生します。 AAAAAAA = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = BBBBBBB) (PORT = 1521) ) ) (CONNECT_DATA = (SERVICE_NAME = CCCCCCC) ) ) AAAAAAA_ADMIN = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP) (HOST = BBBBBBB) (PORT = 1521) ) ) (CONNECT_DATA = (SERVICE_NAME = CCCCCCC) (SERVER = dedicated) ) ) 他に何か変更するファイルがありましたでしょうか? ご存知の方がおられればご教示いただけませんでしょうか? 宜しくお願いします。

  • Perlの書き方

    $addr = $ENV{'REMOTE_ADDR'}; open(IN,"$log"); my @data = <DATA>; foreach(@data){ my($ip)=split(/\,/,$_); if($ip==$addr){$a=1;} if ($a !=1) { 処理1 } else { 処理2 } } close(DATA); $logに$addrが含まれている場合は処理2を実行させたいと↑のスクリプトを書いてみました。私の環境(パソコンの環境と、設置サーバーの環境)では正常に動いているようですが、人に(パソコンの環境と、設置サーバーの環境)よっては、処理1が実行されてしまうようです。書き方は、これで間違っていませんでしょうか? もし間違っていないのでしたら、環境によって$logに$ipが記録されていないのかも知れません。perlの知識はあまりありませんが、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • [Perl]foreach if 抽出

    質問させていただきます。 メールヘッダに対して以下のプログラムを実行します。 ソースコード ~略 my $file_data_str = join("", @file_data); my @received_datas = split(/Received:/, $file_data_str); my @received_datas = reverse(@received_datas); foreach my $sorted(@received_datas){ if($sorted =~ /by\s\w+.abc.jp/){ $sorted =~ /(\[\d+\.\d+\.\d+\.\d+\])/; print $sorted; print "\n"; } } } exit; を実行すると以下のようにに実行結果が出てきます。 from 158.217.207.30 (114.114.96.20 [114.114.96.20]) by ************abc.jp from ****************.jp (***************.jp [158.217.208.15]) by ***********abc.jp 私は [114.114.96.20]だけを取りだしのですがどうしたらいいでしょうか? foreach my $sorted(@received_datas){ if($sorted =~ /by\s\w.abc.jp/){ $sorted =~ /(\[\d+\.\d+\.\d+\.\d+\])/; ここをどうにかすればいけると思うのですが詰まってしまって… 申し訳ないですが助言をお願いします。

    • ベストアンサー
    • Perl
  • Perlの初心者です。2重ループの方法で困ってます。

    ある二つのファイル(moto1.csvとmoto2.csv)の2番目のフィールドが おなじときに二つのファイルの中身をあわせて別のファイル(kekka.csv)を 作る作業をしています。 下記のソースで※2の場所で何回もファイルをオープンさせるととても重いので ※1でファイルを一回だけオープンさせて処理しようと思ったら。 内側のループ(moto2_Log)が一回しか処理されないので困っております。 何かよいアイデアがありましたらよろしくお願いします。 open(moto1_Log,"< moto1.csv"); open(kekka_Log,"> kekka.csv"); ※1open(moto2_Log,"< moto2.csv"); while( <moto1_Log> ) { chop; @moto1_List=split(/,/); ※2 #open(moto2_Log,"< moto2.csv"); while( <moto2_Log> ) { chop; @moto2_List=split(/,/); if($moto1_[1] eq $moto2_List[1]){ print kekka_Log $S_List[0]; print kekka_Log ","; print kekka_Log $S_List[1]; print Export_Log ","; print Export_Log $S_List[2]; print Export_Log ","; print Export_Log $S_List[3]; print Export_Log ":"; print Export_Log $E_List[0]; print Export_Log ","; print Export_Log $E_List[1]; print Export_Log ","; print Export_Log $E_List[2]; print Export_Log ","; print Export_Log $E_List[3]; print Export_Log "\n"; #改行コード continu; } } } close (moto2_Log); close(kekka_Log); close(moto1_Log);

    • ベストアンサー
    • Perl
  • perl 5.8.8 日本語マッチ

    perl5.8.8を使っています。 日本語にマッチする正規表現を書きたいのですが、どうしてもマッチしません。 例えば、以下のファイルtest.txtから「さしすせそ」だけを抽出し、表示させたいです。 ---------test.txt-------------------------------- あいうえお かきくけこ さしすせそ たちつてと -------------------------------------------------- ----------test.pl-------------------------------- use strict; use warnings; open(FILE, 'test.txt') or die "$!"; my @file = <FILE>; close(FILE); foreach my $line (@file){ if($line =~ /^さ/){ print "$line\n"; } } ------------------------------------------------ このtest.plを実行しても「さしすせそ」を抽出することが できません。 どうしたらよいのでしょうか? 自宅の新しいバージョンのperlだとできるのですが 会社のperlは5.8.8で顧客環境でもあるのでバージョンアップも できません。 すみませんが、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • perl 計算結果をファイルへ出力したい

    perl やり始めたばかりです。宜しくお願いします。 入力ファイル data.txt があるとします。 data.txt は、 123 456 789 333 555 777 以上のようなテキストファイルといたします。このファイルを 以下の様に100分の1にして出力したい。 1.23 4.56 7.89 3.33 5.55 7.77 と言うことで、この場で教えていただきました。それが、以下です。 #!/usr/bin/perl open(IN, "data.txt") or die ; @x = <IN>; close (IN); foreach $line (@x){ chomp($line); @elms = split(' ',$line); foreach $data (@elms){ print $data/100," "; } print "\n"; } おかげ様でこれはこれで上手く動きました。そこで、出力値をファイルに 書き込みたいのです。 もちろん、以下の様な方法でファイルに 書き込めるのは判っております。 計算プログラム.pl > outfile.txt しかし、上のプログラムをベースにファイルに書き込めないかと色々と 試してはみましたが、どうも上手く行きません。 どなたか教えて頂けないでしょうか? 宜しくお願い申し上げます。

    • ベストアンサー
    • Perl
  • テキストを参照としたPerlによる名前の変更

    よろしくお願いします。ディレクトリ内のファイル名をテキストデータを参照として変更したいと思っております。まず、以下の参照テキストがあります。 sansyo.txt 1,2,1 2,3,1 3,4,2 4,5,3 6,7,9 ・ ・ ・ ・ このファイルを利用してディレクトリ内のファイルを以下のようにリネームします。 1,2.txt → 1,2,1.txt 2,3.txt → 2,3,1.txt 3,4.txt → 3,4,2.txt 4,5.txt → 4,5,3.txt 6,7.txt → 6,7,9.txt ・ ・ ・ ・ ・ ここで私は以下のプログラムを作成しました。 sansyo.pl ------------------------------ use strict; use warnings; my $dirname = '.'; opendir(DIR, $dirname) or die "$dirname: $!"; while (my $dir = readdir(DIR)) { next unless (-f $dir); next unless ($dir =~ /\.txt$/); print $dir, "\n"; open(FILE, $dir) or die "$dir: $!"; open(FILE2,"sansyo.txt"); my @file = <FILE>; my @file2 = <FILE2>; close(FILE); close(FILE2); foreach my $line2 (@file2) { my ($a,$b,$c) = split(/,/, $line2); if ($dir == $a.",".$b.".txt"){ rename ($dir, $a.",".$b.",".$c.".txt"); } } } closedir(DIR); 内容は、FILE2にsansyo.txtをforeachで1行ずつ読み込んでいき、 $a,$b.txtというファイルが$dirに読み込んだファイルにあったら、 $a,$b,$c.txtというファイルにリネームするという内容です。 ですが、いろいろ試行錯誤したもののうまくいきません。 具体的には、 Argument "1,2.txt" isn't numeric in numeric eq (==) at sansyo.pl line 23. とエラーがでて if ($dir == $a.",".$b.".txt"){ この部分でエラーが発生しているようです。 どなたか解決方法をよろしくお願いします。

    • ベストアンサー
    • Perl