问题是我无法避免处理其中不包含换行符的极大文件:
<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都不允许使用这样的文件。那么,我该如何从中提取匹配?
答案 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
。这将确保只有空字节是行终止符