【问题标题】:Read files searching for a string and print its path读取文件搜索字符串并打印其路径
【发布时间】:2012-06-21 14:12:39
【问题描述】:

我正在尝试在 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);

【问题讨论】:

  • 也许您更愿意使用grep 的众多实现之一,而不是自己滚动。
  • 如上所述,你可以使用 Perl 的grep() 函数。同样根据经验,我建议您输出到 STDIN 而不是文件(只是 print() 它)。您可以使用&gt; 重定向将输出重定向到文件。这允许脚本具有更大的灵活性(例如将输出通过管道传输到另一个进程等...)。
  • 我曾尝试使用 grep,但它并没有给我想要的结果,因为它没有向我显示包含的所有子目录。这就是我试图寻找另一种解决方案的原因。
  • @m0skit0:Perl 的grep 不会这样做:它过滤 Perl 列表而不是文件。而且你不能输出到STDIN :)
  • 好吧,我理解错了这个问题。我以为字符串在文件 name 中:P

标签: string perl file search


【解决方案1】:

你离得不远了,但是有些事情你需要改变。

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

正如其他人在 cmets 中指出的那样,这可以通过递归 grep 轻松解决。但不幸的是,您似乎使用的是 Windows,在这种情况下,它不是一个选项(据我所知)。

【讨论】:

  • 感谢 TLP 的完美工作。那你可以解释一下if(-f $element &amp;&amp; $element =~ /\.txt$/)-f是什么意思。?
  • 描述在perldoc -f "-X"
【解决方案2】:

如果这确实是您需要做的全部,您可以查看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

【讨论】:

    【解决方案3】:

    #! 行在 Windows 平台上无关紧要,在 Unix 上只是一种方便。最好在此处省略。

    您的程序大部分是正确的,但避免了 Perl 为使代码更简洁和易于理解而提供的许多便利。

    您应该始终将use warnings 添加到您的use strict,因为它会发现您可能会忽略的简单错误。

    您的文件打开应该使用词法文件句柄和open 的三参数形式,并且您应该检查它们是否成功,因为打开文件失败会使大多数后续代码无效。一个惯用的 open 看起来像这样

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

    还值得指出的是,+&gt;&gt; 的打开模式打开文件以供 读取 追加,这很难做到。在这种情况下,您的意思只是 &gt;&gt;,但最好打开文件一次,并在程序运行期间保持打开状态。

    这是对您的程序的修改,希望对您有所帮助。它使用正则表达式来检查字符串是否出现在文件的当前行中。 /\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;
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-13
      • 2019-01-28
      • 1970-01-01
      • 2019-06-05
      • 2019-01-29
      • 2015-08-15
      • 1970-01-01
      • 2014-09-06
      相关资源
      最近更新 更多