• ベストアンサー

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の中身がからっぽで ファイルがないことになっています。この違いがどうしてもわかりません。  以上の二点がわからないんですがどうかお手数ですがどなたか教えてください。  

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

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

  • ベストアンサー
  • 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

  • perl上でのgrepでエラーとなる文字の対応

    perlプログラム内で、grepを行っております。 grep対象の中身に +、*、(、)、[、]などの文字列が含まれているため、エラーとなり、 プログラムがうまく動作しません。 grepしたい対象データ例:http://www.XXX.co.jp/○○+▲▲ http://www.XXX.co.jp/○○+▲▲の+を 文字として判断し、正規表現扱いではないとしたい。 http://www.XXX.co.jp/○○+▲▲を含む文字を抽出したい。 perl プログラムにおいて @line1 = grep(/$url/,<ARG>); という記述しておりますが、どのように変更すればよいでしょうか? また、grepしたい対象データがファイルに格納されておりますが、 その中で、+を \+ にファイル一括変換する場合、:%s/+/\+/g で やろうとしても、変換されません。 perlプログラムでの対応、grep元ファイルの変換処理方法 それぞれのやり方について教えてください。

    • ベストアンサー
    • Perl
  • unixのfindコマンド

    unixのfindコマンドで、ある複数のディレクトリから指定のファイル名だけを 検索し、その結果をgrepしたいのですが、 例えば 01_dir 02_dir : 11_di : 21_dir : と言うディレクトリがあります。 そこから、「0」で始まっているディレクトリの中なら拡張子が*.txtを 検索し、その検索したファイルに対して、grepを実行したいのですが、 上手くいきません。 もちろん、各ディレクトリには、「.txt」以外のファイルもありますし、 ファイル名にも条件を付与したいです。 以下の様に、 find . -name "0*_dir" -type d -print | xargs ls -l *.txt | grep "検索文字" find . -name "0*_dir" -type d -print | xargs ls *.txt | grep "検索文字" find . -name "0*_dir" -type d -print | xargs -i ls -l '{} /*.txt' | grep "検索文字" find . -name "0*_dir" -type d -print | xargs -i ls {} "検索文字" とやってみたのですがだめでした。 find ./ -type d \( -name '1_*dir' -o -name '2*_dir' -o -name '3*_dir' \) -prune -o -type f -print と「-prune」で除外するディレクトリを指定すればできなくはないですが、 すべてのディレクトリ書くのはいい方法ではないです。 よい方法をお願いします。 OSは、Solaris 11.3です。

  • 秀丸のgrep検索

    お世話になっております。 「秀丸」のことです。 秀丸のなかにテキストデータが今入っています。 1 日付 時間 データ 2 日付 時間 データ 3 日付 時間 データ というかんじにはいっています。 同じファイルがたくさんあって、ひとつのフォルダに なっています。 そのデータにgrep検索をかけたいのです。 以前検索をかけたときは、 普通に 検索元ファイル名 日付 時間 データ 検索元ファイル名 日付 時間 データ 検索元ファイル名 日付 時間 データ 検索元ファイル名 日付 時間 データ というふうに結果が出たのですが、 ルートディレクトリ?からファイル名が出てきてしまうのです。 具体的には C:¥ABC¥DCV¥UUU\検索元ファイル名 日付 時間 データ というように余計なデータまでくっついてくるのです どうしたらいいでしょうか? なにがわるいのでしょう? ちなみに、 そのデータはネットワークにありましたが、 自分のPC(ローカルに落としてきても) おなじでした どうしたらいいでしょうか?

  • CGIでのgrep関数においての質問

    Perl言語で作成するCGIプログラムについての質問なのですが、grep関数をつかって文字のマッチングを試みて、1回目はうまくいったのですが、同じように2回目を同じプログラムで使ったところ、絶対に0件マッチになります。検索対象も、検索文字列も、スカラー変数でだしてみて目で確認して明らかに合致しているのに0件になります。 ちなみに、使用した関数は以下のような感じです。 @hit = grep(/$data1/,@data2); $hit = grep(/$data1/,@data2); $hitでだしてみても0になりますし、@hitも何も入っていません。 grep関数は2回使えないのでしょうか。 検索文字はメールアドレスなのですが、前のプログラムで同じように関数を使って成功していますので、検索文字が原因ではないと思いますが。 ご回答お願い致します。

    • ベストアンサー
    • Perl
  • 簡易grepコマンドの作成を自作プログラムで作りたいのですが……

    簡易grepコマンドの作成を自作プログラムで作りたいのですが…… C言語でです。 C++ではなぃです。 できれば初心者が考えるよぉなプログラムで。 またコメントみたぃにプログラムの意味も詳しくわかりやすくあると助かります。 コンパイルは ./mygrep 検索するもの ディレクトリ/ファイル名 だった気がします。 mygrepはプログラム名です。 おねがぃします。

  • linux(UNIX) の grep で、あるディレクトリ以下を再帰的に見て、全ての *.html ファイルに grep をかける方法

    linux(UNIX) の grep で、あるディレクトリ以下を再帰的に見て、全ての *.html ファイルに grep をかける方法を教えてください。 簡単な事なのかもしれませんが、コマンドから打つ場合、どのようにすればよいか、分かりません。 Windows の秀丸のgrepなら簡単に出来るのですが。。。 どなたか教えてくださいませ。。。

  • MsDosでファイル名とファイル内の文字列の検索

    リナックスコマンドでいうところの find -name xxxx -exec grep $test {} \;の処理を コマンドプロンプトにて、利用したいと考えています。 dir xxxx /s /b | find "$test" こういった記述で出来るのではないかと考えたのですが。 findが"ファイル名"を検索するためファイルの中身を検索してくれません。 何かいい方法は御座いませんか? また、dirで取得したパスを配列に入れて、foreachでファイルの中身を検索し続けるということは可能でしょうか? よろしくお願いいたします。

  • UNIXコマンド "grep" "find" の使い方教えて下さい。

    1)以下(1)、(2)を検索したいとします。  (1)"wrk_str"という文字列の記述があるファイル名  (2)tmp_file.c という名前のファイル名 2)ディレクトリ構成が以下になってるとします。  /home/users/複数のディレクトリが存在/複数のディレクトリが存在/複数のファイルが存在 3)/home/users/ 配下に検索したい文字列、ファイルがあるとした場合、どのように   探せばいいでしょうか?   /home/users/配下で得に条件なしでgrepすると、"Arg list too long"(量が多い?)の   メッセージが出て、検索できませんでした。 UNIXコマンドに詳しい方、宜しくお願いします。 それ以外にも、色々検索方法知っていたら教えて下さい!!

  • すべてのディレクトリに対してgrepをかける方法について教えてください。

    たとえば、/(ルート)配下にあるすべてのディレクトリ(サブディレクトリ)配下のファイルに対して、'test'という文字列が入っているかどうかを調べたいと思っています。 サブディレクトリは何階層にもなっており、存在するすべてのファイルに対して検索をかけたいと思っています。 以上のような場合にどのようにgrepを使用すればよいのでしょうか? よろしくお願いします。

  • すべてのファイルに対してgrepをかける方法を教えてください。

    /(ルート)配下にあるすべてのディレクトリ(サブディレクトリ)配下のファイルに対して、'test'という文字列が入っているかどうかを調べたいと思っています。 サブディレクトリは何階層にもなっており、存在するすべてのファイルに対して検索をかけたいと思っています。 以上のような場合にどのようにgrepを使用すればよいのでしょうか?

専門家に質問してみよう