删除不是以相同 id 开头的连续 n 行的行

删除不是以相同 id 开头的连续 n 行的行

我有一个如下所示的文件:

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} }
'

相关内容