【问题标题】:Search files and when match is found, store it, then print out 4 lines above, 3 lines below搜索文件,找到匹配项时,存储它,然后打印出上面 4 行,下面 3 行
【发布时间】:2012-05-24 06:48:06
【问题描述】:

我有一个简单的搜索脚本,它接受用户输入并跨目录和文件进行搜索,并且只列出找到它的文件。我想要做的是能够在找到匹配项时,抓住上面的 4 行它,以及它下面的 3 行并打印它。所以,假设我有。

somefile.html

"a;lskdj a;sdkjfa;klsjdf a aa;ksjd a;kjaf ;;jk;kj asdfjjasdjjfajsd  jdjd
jdjajsdf<blah></blah> ok ok okasdfa stes test tes tes test test<br>

blah blah blah ok, I vouch for the sincerity of my post all day long.
Even though I can sometimes be a little crass.

I would only know the blue moon of pandora if I saw it. I heard tales of long ago 
times in which .. blah blah

<some html>whatever some number 76854</some html>

running thru files of grass etc.. ===> more info
whatever more "

假设我想找到“76854”,它将打印或存储在一个数组中,以便我可以打印在目录/文件中找到的所有匹配项。

*Match found:*

**I would only know the blue moon of pandora if I saw it. I heard tales of long ago 
times in which .. blah blah
<some html>whatever whatever</some html>
running thru files of grass etc.. ===> more info
whatever more**


**********************************

类似的东西。到目前为止,我有并且它正在通过打印出找到匹配项的文件来工作:

if ($args->{'keyword'}){
    if($keyword =~ /^\d+$/){
    print "Your Results are as Follows:\n";
        find( sub
            {
                local $/;
                return if ($_ =~ /^\./);
                return unless ($_ =~ /\.html$/i);
                stat $File::Find::name;
                return if -d; #is the current file a director?
                return unless -r; # is the file readable?
                open(FILE, "< $File::Find::name") or return;
                my $string = <FILE>;
                close (FILE);
                print "$keyword\n";
                if(grep /$keyword/, $string){
                    push(@resultholder, $File::Find::name);
                }else{
                   return;
                }
             },'/app/docs/');
    print "Results: @resultholder\n";
    }else{
        print "\n\n ERROR\n";
        print "*************************************\n\n";
        print "Seems Your Entry was in the wrong format \n\n";
        print "*************************************\n\n";
    }
exit;
}

【问题讨论】:

    标签: perl


    【解决方案1】:

    这里是 perl 的先决条件吗?这使用 grep 非常简单,您可以告诉它在匹配前后打印 N 行。

    grep &lt;search-term&gt; file.txt -B &lt;# of lines before&gt; -A &lt;# of lines after&gt;

    如果你真的想使用 perl,请忽略,只是扔掉一个替代品。

    【讨论】:

      【解决方案2】:

      您使用的是 Windows 还是 Linux?

      如果您在 Linux 上,您的脚本最好替换为:

      grep -r -l 'search_string' path_to_search_directory
      

      它将列出所有包含 search_string 的文件。要在 match 行之前获得 4 行上下文,在行之后获得 3 行上下文,您需要运行:

      grep -r -B 4 -A 3 'search_string' path_to_search_directory
      

      如果由于某种原因您不能或不想使用 grep,则需要改进您的脚本。

      首先,通过这种结构,您只读取文件中的第一个字符串:

      my $string = <FILE>;
      

      其次,你最好避免将所有文件读入内存,因为你会遇到几个 Gb 的文件。甚至将一个字符串读入内存,因为你会遇到非常大的字符串。将其替换为对一些小缓冲区的顺序读取。

      最后,要获得之前的 4 行和之后的 3 行,您需要从找到的匹配中执行反向读取(在匹配之前寻找到 buffer_size 的位置,读取该块并检查是否有足够的换行符在里面)。

      【讨论】:

      • “但是它不允许你得到上面 4 行和下面 3 行”。您可以通过将-4 替换为-B 4 -A 3 来做到这一点
      【解决方案3】:

      因此,您需要存储至少 8 行,并在第 5 行与您的模式匹配时输出这 8 行。 shift 运算符,用于从数组的前面删除一个元素,push 运算符,用于将一个元素添加到列表的末尾,在这里可能会有所帮助。

      find( sub {
          ...  # but don't set $\
      
          open( FILE, '<', $File::Find::name) or return;
          my @buffer = () x 8;
          while (<FILE>) {
              shift @buffer;
              push @buffer, $_;
              if ($buffer[4] =~ /\Q$keyword\E/) {
                  print "--- Found in $File::Find::name ---\n";
                  print @buffer;
                  # return?
              }
          }
          close FILE;
      
          # handle the case where the keyword is in the last ~4 lines of the file.
          while (@buffer > 5) {
              shift @buffer;
              if ($buffer[4] =~ /\Q$keyword\E/) {
                  print "--- Found in $File::Find::name ---\n";
                  print @buffer;
              }
          }
      } );
      

      【讨论】:

      • 我是一个 perl 新手,如果我可以根据您提供的代码,我有一些问题。 1. 我的缓冲区 = () x 8;做? 2.移位缓冲器;推送缓冲区,$_; 3. $缓冲区[4] ?
      • 1.创建一个包含 8 个空元素的列表。 2. shift 从列表中删除第一个元素。 3. push 将元素添加到列表末尾。 4. 因为$buffer[4] 是列表中的第 5 个元素。即,它前面有 4 个元素,后面有 3 个元素。
      猜你喜欢
      • 2013-03-21
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 2020-02-01
      相关资源
      最近更新 更多