用awk删除包含唯一第一个字段的行?

时间:2011-02-25 23:24:18

标签: sorting sed awk grep uniq

希望仅打印具有重复的第一个字段的行。例如来自这样的数据:

1 abcd
1 efgh
2 ijkl
3 mnop
4 qrst
4 uvwx

应打印出来:

1 abcd
1 efgh
4 qrst
4 uvwx

(仅供参考 - 我的数据中第一个字段的长度不总是1个字符)

5 个答案:

答案 0 :(得分:5)

awk 'FNR==NR{a[$1]++;next}(a[$1] > 1)' ./infile ./infile

是的,你给它输入两次相同的文件。由于您事先并不知道当前记录是否为uniq,因此您在第一次传递时基于$1构建一个数组,然后您只输出多次看到$1的记录在第二关。

我确信只有一次通过文件才有办法实现,但我怀疑它们会像“干净”一样

解释

  1. FNR==NR:仅当awk正在读取第一个文件时才会出现这种情况。它主要测试所看到的记录总数(NR)与当前文件(FNR)中的输入记录。
  2. a[$1]++:构建一个关联数组 a ,其关键是第一个字段($1),每次看到它的值增加1。
  3. next:如果达到此目的,请忽略脚本的其余部分,重新​​开始使用新的输入记录
  4. (a[$1] > 1)这只会在./infile的第二次传递时进行评估,并且只打印我们不止一次看到的第一个字段($1)的记录。从本质上讲,它是if(a[$1] > 1){print $0}
  5. 的简写

    概念证明

    $ cat ./infile
    1 abcd
    1 efgh
    2 ijkl
    3 mnop
    4 qrst
    4 uvwx
    
    $ awk 'FNR==NR{a[$1]++;next}(a[$1] > 1)' ./infile ./infile
    1 abcd
    1 efgh
    4 qrst
    4 uvwx
    

答案 1 :(得分:1)

这里有一些awk代码可以执行您想要的操作,假设输入已按其第一个字段分组(如uniq也需要):

BEGIN {f = ""; l = ""}
{
  if ($1 == f) {
    if (l != "") {
      print l
      l = ""
    }
    print $0
  } else {
    f = $1
    l = $0
  }
}

在此代码中,f是字段1的前一个值,l是该组的第一行(如果已经打印出来,则为空)。

答案 2 :(得分:1)

BEGIN { IDLE = 0; DUP = 1; state = IDLE }

{ 
  if (state == IDLE) {
    if($1 == lasttime) {
       state = DUP
       print lastline
    } else state = IDLE
  } else {
    if($1 != lasttime)
        state = IDLE
  }
  if (state == DUP)
    print $0
  lasttime = $1
  lastline = $0
}

答案 3 :(得分:0)

假设您在问题中显示的有序输入:

awk '$1 == prev {if (prevline) print prevline; print $0; prevline=""; next} {prev = $1; prevline=$0}' inputfile

该文件只需要读一次。

答案 4 :(得分:0)

如果你可以使用Ruby(1.9 +)

#!/usr/bin/env ruby
hash = Hash.new{|h,k|h[k] = []}
File.open("file").each do |x|
  a,b=x.split(/\s+/,2)
  hash[a] << b
end
hash.each{|k,v| hash[k].each{|y| puts "#{k} #{y}" } if v.size>1 }

输出:

$ cat file
1 abcd
1 efgh
2 ijkl
3 mnop
4 qrst
4 uvwx
4 asdf
1 xzzz

$ ruby arrange.rb
1 abcd
1 efgh
1 xzzz
4 qrst
4 uvwx
4 asdf