🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Q&A

解決済

2回答

1743閲覧

Perlでディレクトリを再帰検索できない

lin.ming

総合スコア50

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

0グッド

0クリップ

投稿2019/09/14 05:49

MacOS(mohave)上で特定の文字列がフォルダ名・ファイル名に含まれているか、Perlで再帰のプログラムを書いたのですが、ちゃんと検索されるフォルダと検索されないフォルダがあります。
チェックしたフォルダ構造は以下です。

/Users/linming/web/members/ +running | +印刷費 | +印刷物.PNG | +copy_recurese.pl | +htaccess | +sfs.cgi | +印刷物.cgi +stats | +controller.php | +model.php | +test.php +test | +hoge.png | +印刷物.png +印刷物 | +印刷代 | +hoge.png | +印刷物.png | +sfs.cgi +sfs.cgi +sfss.cgi +sfsimple.cgi

プログラムは以下です。

Perl

1#!/usr/bin/perl -w 2 3use strict; 4use utf8; 5use CGI; 6use URI::Escape; 7use File::Basename; 8use File::Path; 9use Encode; 10use FindBin; 11binmode STDOUT, ':utf8'; 12 13# initialization. 14my $q = new CGI; 15my $file = ""; 16my @files = (); 17my $dir = ""; 18my @dirs = (); 19my $out = ""; 20 21#GET処理 22my $searchText = ""; 23if($q->request_method eq "GET"){ 24 $searchText = $q->escapeHTML($q->param('text')); 25} 26#ファイル探索 27sub EnumFiles($$@){ 28 my ($dir, $text, @results) = @_; 29 opendir(DIR, decode('UTF-8', $dir)) or die("Can not open directory : $dir\n"); 30 my @files = readdir(DIR) or die("Can not read files : @files\n"); 31 closedir(DIR); 32 33 foreach $file(sort @files){ 34 next if($file =~ /^.{1,2}$/); 35 if(-d $file){ 36 print("Entering $file<br />\n"); 37 if("$dir/$file" =~ /$text/){ 38 push(@results, "$dir/$file"); 39 } 40 @results = &EnumFiles("$dir/$file", $text, @results); 41 } 42 elsif(-f $file){ 43 print("Checking $dir/$file<br />\n"); 44 if("$dir/$file" =~ /$text/){ 45 push(@results, "$dir/$file"); 46 } 47 } 48 } 49 return @results; 50} 51# write header. 52$out = <<"EOM"; 53Content-type: text/html 54 55<?xml version="1.0" encoding="utf-8"?> 56<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 57 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 58<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> 59<head> 60<meta http-equiv = "Content-Type" content = "text/html; charset = utf-8" /> 61<body> 62EOM 63print($out) or die($!); 64 65my $fullpath = decode('UTF-8', uri_unescape($FindBin::Bin)); 66# get files and directories. 67my $decText = decode('UTF-8', $searchText); 68print("<p>Search Text : $decText</p>\n") or die($!); 69print("<ul>") or die($!); 70my @result = (); 71@result = EnumFiles($fullpath, $searchText, @result); 72foreach my $file(@result){ 73 my $basename = decode('UTF-8', $file); 74 $out = <<"EOM"; 75 <li>$basename</li> 76EOM 77 print($out); 78} 79print("</ul>"); 80 81# print footer. 82$out = <<"EOM"; 83</body> 84</html> 85EOM 86print($out) or die($!); 87 88undef($q);

プログラムの実行結果は以下です。

Search Text : cgi Checking /Users/linming/Documents/web/members/.DS_Store Checking /Users/linming/Documents/web/members/copy_recurse.pl Checking /Users/linming/Documents/web/members/meets.bass-world.conf Entering running Checking /Users/linming/Documents/web/members/running/.DS_Store Checking /Users/linming/Documents/web/members/running/copy_recurse.pl Checking /Users/linming/Documents/web/members/running/sfs.cgi Checking /Users/linming/Documents/web/members/sfs.BAK Checking /Users/linming/Documents/web/members/sfs.cgi Checking /Users/linming/Documents/web/members/sfs.cgi.bak20190720 Checking /Users/linming/Documents/web/members/sfss.cgi Checking /Users/linming/Documents/web/members/sfssimple.cgi Entering stats Entering test Entering 印刷物 Checking /Users/linming/Documents/web/members/印刷物/.DS_Store Checking /Users/linming/Documents/web/members/印刷物/sfs.cgi ・/Users/linming/Documents/web/members/running/sfs.cgi ・/Users/linming/Documents/web/members/sfs.cgi ・/Users/linming/Documents/web/members/sfs.cgi.bak20190720 ・/Users/linming/Documents/web/members/sfss.cgi ・/Users/linming/Documents/web/members/sfssimple.cgi ・/Users/linming/Documents/web/members/印刷物/sfs.cgi

web/members配下のディレクトリを全て舐めていないように思えます。
日本語のディレクトリでうまくいかないのなら、encode/decodeの処理が間違っているからだと思いますが、1バイトコードのディレクトリでもうまく言っていません。(上記「stats」「test」配下)
原因は何でしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

"Entering stats"までは到達しているようなので、そこからデバッガでステップ実行してみれば原因が特定できるでしょう。

  1. perl -d スクリプト名
  2. プロンプトが出たらデバッグコマンドでブレイクポイント設定 b 行番号 if $file eq 'stats'

ここで行番号はif(-d $file){の行でいいでしょう。
3. cでブレイクポイントまで実行
4. 止まったらnでステップ実行。期待通りにループ内の分岐を進まないなら条件式を見直す。p 式で任意の条件式や変数の中身を確認できる。

デバッガのl,c,n,b,q コマンドをまず覚えましょう。

しかし、こういう処理を実行したいときのお勧めは、自前で再帰呼び出し関数を苦労して書くのではなく、File::Findモジュールを使うことです。

最短でFile::Findなスクリプトを作る方法

  1. find2perl . -name home > test.pl 書式は標準findコマンドとほぼ同じ。ファイルの処理を実行する代わりにスクリプトのひな形が出力される。
  2. できたtest.plのsub wantedの中にファイルごとにやりたい処理を書く。対象ディレクトリ名とファイル名は初めから$dir, $nameで参照できるようになっている。

投稿2019/09/14 09:07

KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lin.ming

2019/09/14 10:05

具体的なご示唆およびデバッガの使い方、ありがとうございました。 今回はnomuken様をベストアンサーにしましたが、KojiDoi様もベストアンサーにしたいぐらいでした。 ありがとうございました。
guest

0

ベストアンサー

対象がファイルでもディレクトリでもない可能性(例えばシンボリックリンク)を考えてfilesの要素数やelseブロックを追加してデバッグ出力してみるのはどうでしょうか?

投稿2019/09/14 07:58

nomuken

総合スコア1627

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lin.ming

2019/09/14 10:02

ご教示ありがとうございます。 シンボリックリンク等ではなくファイルなのは確認しているのですが、 elsif(-f $file){ を else{ に変えたらちゃんと走査するようになりました。日本語のファイルも思った通りの挙動になりました。 ありがとうございました。
nomuken

2019/09/14 11:55

よく考えたら elsif(-f $file) はフルパスで判定していないので'/Users/linming/web/members/'直下だけしか正しく判定できないと思います。
lin.ming

2019/09/14 12:01

あ、なるほど。 ご指摘ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問