• ベストアンサー

grepの書き方がわかりません。

Perlの初心者なんですが、以下のようなテーマをもらってプログラムを作っています。  第一引数にディレクトリのパス、第二引数に検索し たいファイル名を指定して第一引数の  パス以下にある全てのディレクトリを検索してファイルがあればそのパスを表示させなさい。 一応できたのですがプログラムの記述の一部がよくわかりません。以下のプログラムは一部です。 local ($dir, $file) = @_; opendir(DIR,$dir) or die @data = readdir(DIR);#ディレクトリの内容を読む closedir(DIR);#ディレクトリを閉じる local @fname = grep {-f "$dir/$_"} @data; local @dname = grep {-d "$dir/$_"} @data; $dir,$fileには第一、第二引数の文字列をいれているのですがそのディレクトリになかにファイル、ディレクトリがないか検索するためgrepを使っています。それで"$dir/$_"の部分の意味がよくわかりません。 この部分は他のサイトであったものを流用しただけなのですがよくわからないまま使ってたまたま動いたから使用しててこのままでは理解していないままなので どうか教えてほしいです。 あともう一点ありましてgrepのところで最初自分で書いた時  local @fname = grep (-f,@data); というように書きました。ファイルが第一引数にあるときは問題なく動作するのですがその下にあるディレクトリにあるとなぜかプログラムが終わりません。 デバッグとして@dataの中身を表示したらそのディレクトリの検索をしてはいるんですが、その中に目当てのファイルがあるはずなのに@dataの中身がからっぽで ファイルがないことになっています。この違いがどうしてもわかりません。  以上の二点がわからないんですがどうかお手数ですがどなたか教えてください。  

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

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

自分でもたまにやるんですが, 「readdir で読み込んで得られるのはファイル名だけ」です. たとえば opendir(DIR, "どこか/遠い/ところ"); @data = readdir(DIR); close(DIR); とやっても @data の要素に "どこか/遠い/ところ" というパスは付きません. だから grep -f, @data とやると, @data の各要素を「カレントディレクトリにあるファイル名」と解釈します.

bfokina
質問者

お礼

なるほど、よくわかりました。 私でもよくわかるくらい丁寧な説明、どうもありがとうございました。

その他の回答 (5)

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

>なぜか何も起こらないのです。 #5で書かれている通りです。 -f $_ がカレントディレクトリのファイルとして調べられるので、テストに合格しないということですね。

bfokina
質問者

お礼

説明不足な点が多かったのに何回も回答して くださってありがとうございました。 助かりました。

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

#1補> 試してみましたが、ディレクトリがネストしている場合でも、うまく動きました(というか質問でおっしゃるような症状がでませんでした) 強いていうなら 関数内で使う変数は全部($data1 も) my で使うほうがいいと思います。

bfokina
質問者

補足

こちらの手違いできちんと動くプログラムをのっけてしまいました。最初gerp関数を使用している2行は local @fname = grep (-f ,@data); local @dname = grep (-d , @data); このように書いていたのです。それで例えば 引数でC:\A\B,test.txtというものにしたとして Bというフォルダにこのファイルが存在すれば問題なく動作するのですが、Bの下にCというフォルダがあって このファイルがCの中にある時、私のほしい結果とでは C:\A\B\C\test.txt となってほしいのになぜか何も起こらないのです。 この書き方ではなぜだめなのかわかりません。サイトでgrepの表記を調べると、 真の要素 = grep(/検索対象文字列/,対象の配列); とあったのでこれを参考にしました。 何度もすいませんがお手数でなければよろしくお願いします。

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

えと.... local @fname = grep {-f "$dir/$_"} @data; ではディレクトリの区切として / を使っているのに &search($dir . "\\" . $data1,$file); では \ を使っているというのが若干気になってみたり. 全部 / に統一しちゃっていいんじゃない? ちなみに手元では (それなりに) うまく動いている模様.

bfokina
質問者

補足

確かに変ですね。ありがとうございました。あと こちらの手違いできちんと動くプログラムをのっけてしまいました。最初gerp関数を使用している2行は local @fname = grep (-f ,@data); local @dname = grep (-d , @data); このように書いていたのです。それで例えば 引数でC:\A\B,test.txtというものにしたとして Bというフォルダにこのファイルが存在すれば問題なく動作するのですが、Bの下にCというフォルダがあって このファイルがCの中にある時、私のほしい結果とでは C:\A\B\C\test.txt となってほしいのになぜか何も起こらないのです。 この書き方ではなぜだめなのかわかりません。サイトでgrepの表記を調べると、 真の要素 = grep(/検索対象文字列/,対象の配列); とあったのでこれを参考にしました。 何度もすいませんがお手数でなければよろしくお願いします。

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

readdir で読み込んだリスト中に '.' とか '..' とかがあるはずです. 何も考えないとこいつらのせいで無限再帰を起こします. ど~でもいいんですが, なぜ今さら local?

bfokina
質問者

補足

myでよかったんですね。逆に勘違いして使ってしまってました。ありがとうございます。 あと'.' とか '..' は気がついて一応したに処理を施しています。以下にプログラム全体を載せます。 &search($ARGV[0], $ARGV[1]); sub search{ local ($dir, $file) = @_; opendir(DIR,$dir) or die "ファイルが見つかりませんでした。"; @data = readdir(DIR); closedir(DIR);#ディレクトリを閉じる local @fname = grep {-f "$dir/$_"} @data; local @dname = grep {-d "$dir/$_"} @data; foreach $data1(@fname){ if($file =~ $data1){ print "$dir\\$data1\n"; } } foreach $data1(@dname){ if($data1 ne "." && $data1 ne ".."){ &search($dir . "\\" . $data1,$file); } } return; }

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

>"$dir/$_"の部分の意味がよくわかりません Perl では、""で囲まれた部分にある変数は展開されます。 $_ は、Perl の特殊変数で、この場合、配列 @data の中身が1つずつ$_ に設定されて { } の部分が実行されます。 $dir が "c:/data" で @data が ("a","b","c") のような場合、 "$dir/$_" は、 "c:/data/a" "c:/data/b" "c:/data/c" のようになります。 >なぜかプログラムが終わりません。 こちらについては、具体的なプログラムが示されていないのでわかりません。

bfokina
質問者

補足

すいません。以下にプログラムを載せます。 &search($ARGV[0], $ARGV[1]); sub search{ local ($dir, $file) = @_; #サブルーチンへの引数を順に代入 opendir(DIR,$dir) or die "ファイルが見つかりませんでした。"; @data = readdir(DIR); closedir(DIR); local @fname = grep {-f "$dir/$_"} @data; local @dname = grep {-d "$dir/$_"} @data; foreach $data1(@fname){ if($file =~ $data1){ print "$dir\\$data1\n"; } } foreach $data1(@dname){ if($data1 ne "." && $data1 ne ".."){ &search($dir . "\\" . $data1,$file); } } return; }

関連するQ&A

専門家に質問してみよう