2012-06-19 2 views
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); 
+3

아마도 자신의 롤링 대신에 많은 구현 중 하나 인'grep'을 사용하는 것을 선호 할 것입니다. – bluevector

+0

위와 같이 Perl의'grep()'함수를 사용할 수 있습니다. 또한 경험에 비추어 볼 때, 파일 대신에 STDIN으로 출력하는 것을 추천한다 ('print()'). '>'리디렉션을 사용하여 출력을 파일로 재지 정할 수 있습니다. 이렇게하면 스크립트에 더 많은 유연성 (예 : 출력을 다른 프로세스 등으로 파이핑)을 할 수 있습니다. – m0skit0

+0

grep 사용을 시도했지만 원하는 하위 결과를 모두 보여주지 못해 원하는 결과를 얻지 못했습니다. 그것이 내가 다른 해결책을 찾으려고 노력하는 이유입니다. –

답변

2

너무 멀지는 않지만 변경해야 할 것이 있습니다.

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

그리고 단지 STDOUT에 출력을 인쇄 :

#!/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 
} 

더 나은 하드 코딩 된 값을 포기하고 특정 출력 파일을 건너 뛸 것입니다.

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

사용법 :

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

다른 사람이 코멘트에서 언급 한 바와 같이,이 쉽게 재귀 grep 해결 될 것입니다. 하지만 불행히도 당신은 윈도우를 사용하고있는 것 같아요. 그런 경우에는 옵션이 아닙니다. (제가 아는 한).

+0

TLP의 작업을 완벽하게 감사드립니다. 그렇다면 'if (-f $ element && $ element = ~/\. txt $ /)'에'-f'의 의미를 설명 할 수 있습니다. – mkHun

+1

이것은''perldoc -f "-X"'] (http://perldoc.perl.org/functions/-X.html)에 설명되어 있습니다. – TLP

0

#! 행은 Windows 플랫폼과 관련이 없으며 Unix에서만 편리합니다. 여기서 생략하는 것이 가장 좋습니다.

프로그램은 대부분 정확하지만 코드가 간결하고 이해하기 쉽도록 Perl이 제공하는 많은 편의를 피합니다.

use strict에는 항상 간과 할 수있는 간단한 오류가 나타나므로 use warnings을 항상 추가해야합니다.

파일 열기는 어휘 파일 핸들과 세 개의 매개 변수 형식 인 open을 사용해야하며 파일을 열지 못해 대부분의 후속 코드가 무효화되므로 성공 여부를 확인해야합니다. 관용적 개방은 또한 +>>의 오픈 모드를 모두이 및 nadle에 어려운 APPEND 읽기 의 파일을 여는 것을 지적 worh되는이

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

것 같습니다. 이 경우에는 단지 >>을 의미하지만 프로그램을 실행하는 동안 파일을 한 번 열어 두는 것이 가장 좋습니다.

이것은 프로그램을 재 작업 한 것으로, 귀하를 돕기를 바랍니다. 정규식을 사용하여 문자열이 파일의 현재 줄에 나타나는지 확인합니다. /\Q$string/$_ =~ /\Q$string/과 동일합니다. 즉, 기본적으로 $_ 변수를 테스트합니다. 정규 표현식에서 \Qquotemeta이며 정규 표현식에서 특수 문자로 작동 할 수있는 문자열의 모든 문자를 이스케이프 처리하고 검색의 의미를 변경합니다.

File::Findwanted 서브 루틴 내에서 $_ 현재보고 작업중인 디렉토리는 현재보고있는 파일이있는 디렉토리로 설정됩니다. $_은 경로없이 파일 이름으로 설정되고 $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; 
    } 
    } 
} 
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 
관련 문제