-2

私はperlスクリプトの問題を抱えています。File :: Findモジュールを使用するスクリプトを作成しました。このモジュールは、引数ディレクトリとして指定されたものから再帰的にウォークし、見つかったすべての*.txtファイルに対して関数を実行することになっています。この問題を簡略化して、主要部分のみを表示しました。

それを実行して私の問題を再現するには、2つのファイルを含むディレクトリを作成する必要があります。 fist.txtそれぞれsecond.txtに2行のみが 含まれます。

cat fist.txt
AAA
BBB

cat second.txt
AAA
BBB

#!/usr/bin/perl
use File::Find;

$ARGS_NUM = $#ARGV + 1;
if ($ARGS_NUM != 1) {
   print "Add start directory as an argument!\n";
   exit(-1);
}

my $DEST_DIR =$ARGV[0];    
find(\&splitter, $DEST_DIR);

sub splitter {
 if (-f $_ && /\.txt$/) {
    $DOC_FILE_NAME = $_;
    print "processing: $DOC_FILE_NAME\n";
    open $DOC_FILE, "<"."$DOC_FILE_NAME" or die "Could not open $DOC_FiLE\n";

    print "Entering first WHILE, DOC_FILE = $DOC_FILE\n";
    $AAA_FOUND = 0;
    $BBB_FOUND = 0;
    while(<$DOC_FILE>) {
      print "first_while\n";
      if (m/^AAA$/i) {
        print "FOUND: AAA in $DOC_FILE\n";
        $AAA_FOUND = 1;
        next;
      }

      if (m/^BBB$/i) {
        print "FOUND: BBB in $DOC_FILE\n";
        $BBB_FOUND = 1;
        next;
      }
    }
    #################### SECOND WHILE WCHICH FAILS.... #################
    $/="";
    seek $DOC_FILE,0,0;
    $QQQ_FOUND = 0;
    print "Entering second WHILE, DOC_FILE = $DOC_FILE\n";
    while(<$DOC_FILE>) {
      print "second_while\n";
      s/\n//g; s/$/\n/; s/^\s*//;
      if ($QQQ_FOUND == 1) {
        $question_text = $_;
        print "question_text = $question_text\n";
        last;
      }

      if (m/^QQQ.*$/i) {
        $QQQ_FOUND=1;
      }
    }
    $/ = undef;
    print "AAA = $AAA_FOUND\n";
    print "BBB = $BBB_FOUND\n";
    print "QQQ = $QQQ_FOUND\n";
    close $DOC_FILE;
  }
}

出力は次のとおりです。

processing: first.txt
Entering first WHILE, DOC_FILE = GLOB(0x13087e0)
first_while
FOUND: AAA in GLOB(0x13087e0)
first_while
FOUND: BBB in GLOB(0x13087e0)
Entering second WHILE, DOC_FILE = GLOB(0x13087e0)
second_while
AAA = 1
BBB = 1
QQQ = 0
processing: second.txt
Entering first WHILE, DOC_FILE = GLOB(0x13087e0)
first_while
Entering second WHILE, DOC_FILE = GLOB(0x13087e0)
second_while
AAA = 0
BBB = 0
QQQ = 0

編集:あなたが見ることができるように、2番目のループは値AAAとBBBの検索を逃します。

4

2 に答える 2

4

確かに、これはslurpモードを有効にするように設定$/しているためです(「への1回の呼び出しでファイル全体を読み取ることを意味します)。のデフォルトはではありません。undef<>$/undef"\n"

local $/;とにかく手動でリセットしようとするのではなく、単に使用する必要があります。

于 2012-11-29T17:28:25.553 に答える
0

多くの人がFile::Find迷惑だと感じます。単に正常に機能しません。それは良いプログラミング慣行を破ります。

これを使用する最良の方法は、必要なサブルーチンの外部にリスト変数を設定し、それを使用して条件に一致するファイルを保存することです。その後、実際の作業のために通常のプログラムに戻ることができます。

my @file_list;
find ( &wanted, $DEST_DIR);

sub wanted {
    next unless -f and  /\.txt$/;
    push @file_list, $File::Find::name;
}

# Now use @file_list to do what you need:
for my $file (@file_list) {
   yadda, yadda, yadda
}

必要な関数は非常に短いため、関数内で必要な関数を組み合わせることができますfind

find (
    sub {
          next unless -f and /\.txt$/;
          push @file_list, $File::Find::name;
       }, 
    $DEST_DIR
);
于 2012-11-29T17:32:24.707 に答える