如果不包含换行符,如何从极大文件中复制匹配项?

时间:2015-06-17 04:09:55

标签: python linux bash perl grep

问题是我无法避免处理其中不包含换行符的极大文件:

<a>text1</a>...gigabytes of data here, all in one single line...[a text to extract b>

如果我想复制此文件中的匹配项(为方便起见,将每个匹配项放在一个单独的行中),该怎么办?说,<b>.*?</b>

如果我使用

grep -Pzo '\[a .*? b>' path/to/input.txt > path/to/output.txt

它只会出错:内存耗尽(这是一个相关问题:grep-memory-exhausted)。
sed和awk都不允许使用这样的文件。那么,我该如何从中提取匹配?

2 个答案:

答案 0 :(得分:2)

#!/usr/bin/perl

use strict;
use warnings;

use constant BLOCK_SIZE => 64*1024;

my $buf = "";
my $searching = 1;
while (1) {
   my $rv = read(\*STDIN, $buf, BLOCK_SIZE, length($buf));
   die($!) if !defined($rv);
   last if !$rv

   while (1) {
      if ($searching) {
         my $len = $buf =~ m{\[(?:a|\z)} ? $-[0] : length($buf);
         substr($buf, 0, $len, '');

         last if $buf !~ s{^\[a}{};

         $searching = 0;
      } else {
         my $len = $buf =~ m{b(?:>|\z)} ? $-[0] : length($buf);
         print substr($buf, 0, $len, '');

         last if $buf !~ s{^b>}{};

         print("\n");
         $searching = 1;
      }
   }
}

做出了很多假设:

  • 假设开始标记拼写为[a
  • 假设结束标记拼写为b>
  • 假设每个开始标记都有相应的结束标记。
  • 假设每个结束标记都有相应的开始标记。
  • 假设在[a[a之间找不到b>

答案 1 :(得分:0)

Grep从版本2.21开始different behavior

  

当搜索二进制数据时,grep现在可以将非文本字节视为行   终止。这可以显着提升性能。

所以现在发生的是二进制数据,所有非文本字节 (包括换行符)被视为行终止符。如果你想改变它 行为,你可以:

  • 使用--text。这将确保只有换行符是行终止符

  • 使用--null-data。这将确保只有空字节是行终止符

--line-regexp option with null data