2

特定のディレクトリとすべてのサブディレクトリを検索するスクリプトを Perl で作成しようとしています。これの目的は、スクリプトがディレクトリ内のすべてのファイルとすべてのサブディレクトリを読み取って、特定のテキスト文字列 (私が定義した任意の文字列) を探す必要があることです。ファイル内に文字列が見つかった場合、スクリプトはファイルのパスと名前を新しいテキスト ファイルに出力し、ディレクトリ ツリー内のすべてのファイルを続行します。

このようなものがありますが、続行する方法がわかりません。私は Perl の初心者であり、このすべてのオプションについて手がかりがありません。

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

my $dir = 'C:\PATH\TO\DIR';
my $string = "defined";

find(\&printFile, $dir);
sub printFile {
   my $element = $_;
   open FILE, "+>>Results.txt";
   if(-f $elemento && $elemento =~ /\.txt$/) {
       my $boolean = 0;
       open CFILE, $elemento;
       while(<CFILE>) {  
           if ($string) {
               print FILE "$File::Find::name\n"; 
           }
           close CFILE;
      }
   }
   close FILE;
}

sleep(5);
4

3 に答える 3

2

あなたはそれほど遠くはありませんが、変更する必要があることがいくつかあります。

#!/usr/bin/perl
use strict;
use warnings;  # never go without warnings
use File::Find;

my $dir = 'C:\PATH\TO\DIR';
my $string = "defined";
open my $out, ">>", "Results.txt" or die $!;  # move outside, change mode, 
                                              # 3-arg open, check return value
find(\&printFile, $dir);

sub printFile {
   my $element = $_;
   if(-f $element && $element =~ /\.txt$/) { # $elemento doesn't exist
       open my $in, "<", $element or die $!;
       while(<$in>) {
           if (/\Q$string\E/) {  # make a regex and quote metachars 
               print $out "$File::Find::name\n"; 
               last;             # stop searching once found
           }
      }
   }  # lexical file handles auto close when they go out of scope
}

さらに良いのは、ハードコードされた値を無視して、特定の出力ファイルをスキップすることです。

my $dir = shift;
my $string = shift;

そして、出力をSTDOUTに出力します。

print "$File::Find::name\n"; 

使用法:

perl script.pl c:/path/to/dir > output.txt

他の人がコメントで指摘しているように、これは再帰的に簡単に解決できますgrep。しかし、残念ながら、あなたはWindowsを使用しているようです。その場合、それはオプションではありません(私が知る限り)。

于 2012-06-19T14:23:51.203 に答える
1

これだけで本当に必要な場合は、 を参照してくださいack。デフォルトでサブディレクトリを検索し、grep に対するその他の機能強化も行います。もちろん、これがより大きなPerlスクリプトに対するものである場合は、シェルアウトするか、他の投稿された回答のいずれかを使用できます.

$ ack include

のようなものを返します

src/draw.c
27:#include <stdio.h>
28:#include <stdlib.h>
29:#include "parsedef.h"
31:#include "utils.h"
32:#include "frac.h"
33:#include "sscript.h"

src/utils.c
27:#include <stdio.h>
28:#include <stdlib.h>
29:#include <string.h>

... 等々

代わりに、一致するファイルの名前のみが必要な場合は、-lフラグを使用します

$ ack -l include

lib/Text/AsciiTeX.xs
src/limit.c
src/sscript.c
src/dim.c
src/frac.c
src/brace.c
src/symbols.c
src/sqrt.c
src/array.c
src/ouline.c
src/draw.c
src/utils.c
src/asciiTeX.c
于 2012-06-19T14:44:06.787 に答える
0

この#!行は、Windowsプラットフォームでは無関係であり、Unixでは便利なだけです。ここでは省略した方がいいです。

あなたのプログラムはほとんど正しいですが、コードをより簡潔で理解しやすくするためにPerlが提供する多くの便利さを避けています。

見落としがちな単純なエラーが発生するため、常に追加する必要use warningsがあります。use strict

ファイルを開くには、字句ファイルハンドルとの3つのパラメーター形式を使用する必要があります。ファイルopenを開かない場合は、後続のほとんどのコードが無効になるため、それらの成功を確認する必要があります。慣用的なオープンは次のようになります

open my $fh, '<', 'myfile' or die $!;

また、オープンモードでは、読み取りと追加の両方+>>でファイルを開くことができますが、これは簡単に説明するのが困難です。この場合は単にを意味しますが、ファイルを一度開いて、プログラムの実行中は開いたままにしておくことをお勧めします。>>

これはあなたのプログラムの作り直しであり、あなたの助けになることを願っています。正規表現を使用して、ファイルの現在の行に文字列が表示されているかどうかを確認します。/\Q$string/と同じです。つまり、デフォルトで変数を$_ =~ /\Q$string/テストします。正規表現内のは、です。これは、正規表現$_内で特殊文字として動作し、検索の意味を変更する可能性のある文字列内の文字をエスケープします。\Qquotemeta

File::Find wantedサブルーチン内では$_、現在の作業ディレクトリが、報告されている現在のファイルを含むディレクトリに設定されていることに注意してください。$_はファイル名(パスなし)に$File::Find::name設定され、完全な絶対ファイルとパスに設定されます。$_現在のディレクトリはファイルを含むディレクトリであるため、パスが必要ないため、ファイルを開くだけで簡単に実行できます。

use strict;
use warnings;

use File::Find;

my $dir = 'C:\path\to\dir';
my $string = 'defined';

open my $results, '>', 'results.txt' or die "Unable to open results file: $!";

find (\&printFile, $dir);

sub printFile {

  return unless -f and /\.txt$/;

  open my $fh, '<', , $_ or do {
    warn qq(Unable to open "$File::Find::name" for reading: $!);
    return;
  };

  while ($fh) {
    if (/\Q$string/) {
       print $results "$File::Find::name\n";
       return;
    }
  }
}
于 2012-06-19T14:25:29.573 に答える