【问题标题】:Removing lines containing a unique first field with awk?用awk删除包含唯一第一个字段的行?
【发布时间】:2011-07-04 16:11:30
【问题描述】:

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

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

应该打印出来:

1 abcd
1 efgh
4 qrst
4 uvwx

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

【问题讨论】:

    标签: sorting sed awk grep uniq


    【解决方案1】:
    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),每次看到它的值都会增加一个。
    3. next:如果达到此条件,请忽略脚本的其余部分,从新的输入记录重新开始
    4. (a[$1] > 1) 这只会在./infile 的第二次通过时评估,并且它只打印我们不止一次看到的第一个字段 ($1) 的记录。本质上,它是if(a[$1] > 1){print $0} 的简写

    概念证明

    $ 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
    

    【讨论】:

    • 谢谢!另外我不知道使用两个文件输入到 awk。 (仅供参考 - 到目前为止,其他答案也有效,谢谢!)
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:
      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
      }
      

      【讨论】:

        【解决方案4】:

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

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

        文件只需读取一次。

        【讨论】:

          【解决方案5】:

          如果你可以使用 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
          

          【讨论】:

            猜你喜欢
            • 2020-11-11
            • 1970-01-01
            • 1970-01-01
            • 2015-09-13
            • 2012-09-19
            • 2013-05-03
            • 1970-01-01
            • 2014-04-07
            • 1970-01-01
            相关资源
            最近更新 更多