我有一个如下所示的文件:
194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5
194136,39.9,36.3
194136,45.2,37.8
194170,46.9,42.2
...
我想保留前六行(以 194104 开头),然后删除接下来的两行,因为只有两行以该数字开头。文件的其余部分也是如此。
可以使用 sed/awk/grep 或其他 unix 工具来完成吗?
答案1
可以使用 sed/awk/grep 或其他 unix 工具来完成吗?
是的。
...
可以使用 awk 或 perl 等工具在大约 20 行代码中完成。
$ cat t.txt
194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5
194136,39.9,36.3
194136,45.2,37.8
194170,46.9,42.2
$ perl t.pl t.txt
194104,41.8,38.3
194104,46.7,39.6
194104,47.4,39.7
194104,49.8,44.3
194104,50.8,47.5
$ wc -l t.pl
19 t.pl
我使用的基本思想是
- 循环输入一次一行
- 将行附加到缓冲区
- 检查第一个单词的值
- 记录它被观看的次数
- 如果不同,则决定是否打印并刷新缓冲区,重置计数
伪代码
这与我的 perl 代码逐行对应,但 perl 更简洁一些(并且我拥抱我的其他代码,尽管 Larry 不赞成)。
let my minimum be 5
let my buffer be blank
let my count be zero
let my prior first word be blank
while read a line
if there is a numeric first word followed by a comma
then
if that first word was the same as my prior first word
then
increment my count
otherwise
if my count is greater than or equal to my minimum
then
print my buffer
end if
empty my buffer
let my count be one
end if
let my prior first word be the one I just read
append the line I just read to my buffer
end if
end while
它可能可以用更少的行或较长的一行来完成。
答案2
该规范可能有点含糊,因为不清楚您是否希望有完全相同或至少六行具有相同的前缀。另一方面,在您的示例中,头部只有 5 行此类代码,这在我测试时造成了一些混乱(我应该先数一下再拍摄):
$ cat 6lines.awk
$1 == prev {
++cnt
block = block $0 RS
if (cnt == 6) {
printf block
cnt = 0
block = ""
}
next
}
{
block = $0 RS
prev = $1
cnt = 1
}
awk -F, -f 6行.awk 输入
我们利用 awk 将未分配的所有内容视为空字符串(此处为上一个)。
答案3
这似乎可以解决问题:
perl -F, -ane '
if ($. > 1) {
if (@q == 6) { print @q; undef @q }
elsif ($F[0] ne $prev) { undef @q }
}
push @q, $_;
$prev = $F[0];
END { if (@q == 6) {print @q} }
'