我有一个数据聚集在一个按块组织的文件中
---- BLOCK ONE ----
some data
another data
more data
more data
-------------------
---- BLOCK two ----
some data
another data
-------------------
---- BLOCK THREE ----
some data
another data
more data
-------------------
等等。总共大约有 2000 个区块。
我需要提取那些少于 4 个条目(数据行)的块。知道如何做到这一点(perl 首选;)
答案1
$ perl -00 -F'\n' -n -e '
$file = shift @F;
pop @F;
if (@F < 4) {
$file =~ s/^---- | ----//g;
open(OUT, ">", $file.".txt");
print OUT join("\n", @F), "\n"
}' input.txt
这个 perl 单行语句用于-00
以段落模式读取输入(由两个或多个换行符分隔),-F
自动将换行符上的输入分割到数组 @F 中,并-n
自动读取输入而不打印它(类似于sed -n
)。
首先,它使用shift 将@F 的第一个元素放入变量$file 中。然后 pop @F 丢弃最后一个元素 ( -------------------
)。如果剩余元素少于 4 个,则:从 $file 中删除----
和----
,打开“$file.txt”进行写入,并将数组的其余部分打印到该文件。
如果您不喜欢这些文件名,您可以使用其他方法 - 例如增加计数器变量,例如在块$file = sprintf "file%04i.txt", ++$counter
内if
而不是使用s///
运算符。
顺便说一句,如果您想保留页眉---- BLOCK...
和页脚,请将和行------*
替换为并将测试更改为.shift
pop
$file = $F[0]
if
if (@F < 6)
示例输出(用于tail
打印文件名):
$ tail BLOCK*.txt
==> BLOCK THREE.txt <==
some data
another data
more data
==> BLOCK two.txt <==
some data
another data
与独立脚本相同,但使用计数器生成文件名:
$ cat split-blocks.pl
#!/usr/bin/perl
use strict;
my $counter;
$/='';
while(<<>>) {
my @lines = split /\n/;
my $file = shift @lines;
pop @lines;
if (@lines < 4) {
$file = sprintf 'file%04i.txt', ++$counter
open(OUT, ">", $file) || die "couldn't open $file for write: $!\n";
print OUT join("\n", @lines), "\n"
}
};
$ ./split-blocks.pl input.txt
$ tail file*
==> file0001.txt <==
some data
another data
==> file0002.txt <==
some data
another data
more data
答案2
这是一个简单的单行:
$ perl -00 -lne '@k=(/\n/mg); print if $#k < 4 ' file
---- BLOCK two ----
some data
another data
-------------------
---- BLOCK THREE ----
some data
another data
more data
-------------------
打开-00
“段落模式”,将由空行分隔的每个行块视为单个“行”。向每个调用添加-l
一个换行符print
,并从每个输入“行”中删除尾随换行符,这意味着“在输入的每一行上-n
运行由 给出的脚本”。-e
脚本本身\n
在输入“行”(段落)中查找字符并将它们存储在数组中。然后,如果数组的最大索引小于 4,我们将打印该行。请记住,数组从 开始计数0
,因此这意味着如果我们的行数少于 4,因为第一行也被计算在内,但最后一行则不计算,因为它的尾随换行符已被 删除-l
,那么数组中的行数少于 4堵塞。
答案3
使用任何awk
:
awk 'NF && !/^-/{ buf= buf (data?ORS:"") $0; data++ }
/^-+$/{ if(data<4) { print (ors?ORS:"") buf; ors=ORS }; buf=data="" }' infile
输出:
some data
another data
some data
another data
more data
如果您想保留块页眉/页脚:
awk 'NF{ buf= buf (data?ORS:"") $0; data++ }
/^-+$/{ if(data<=5) { print (ors?ORS:"") buf; ors=ORS }; buf=data="" }' infile
输出:
---- BLOCK two ----
some data
another data
-------------------
---- BLOCK THREE ----
some data
another data
more data
-------------------
答案4
perl -lne '
if (/^-+$/) {
print join "\n", @M, $_ if $#M < 4;
@M = ();
next;
}
if (/^-/) {
$M[0] = $_;
next;
}
push @M, $_ if $#M >= 0;
' file
由于禁用了自动打印选项,perl
逐行读取文件。perl
(-n)
然后如果我们在某个部分内,(push @M, $_ if $#M >= 0)
将该线推入数组内。
如果我们在结束部分内(/^-+$/)
并且数组长度小于 4,则打印它并清空数组(@M = ())
。
否则,我们开始一个部分(/^-/)
,并将当前行保存为数组中的第一个值,然后它就成为标题。
我已经删除了空行,但如果愿意,您可以保留它。