4

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

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

应该打印出来:

1 abcd
1 efgh
4 qrst
4 uvwx

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

4

5 回答 5

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

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

我敢肯定有一些方法可以只通过文件一次,但我怀疑它们会像“干净”一样

解释

  1. FNR==NRawk:这仅在读取第一个文件时才成立。它本质上是测试看到的记录总数 (NR) 与当前文件中的输入记录 (FNR)。
  2. a[$1]++: 构建一个关联数组,其中谁的键是第一个字段 ( $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
于 2011-02-25T23:33:04.230 回答
1

这是一些 awk 代码来做你想做的事,假设输入已经按它的第一个字段分组(就像uniq也需要):

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

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

于 2011-02-25T23:38:36.417 回答
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
}
于 2011-02-25T23:41:16.737 回答
0

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

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

该文件只需读取一次。

于 2011-02-26T01:33:07.137 回答
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
于 2011-02-26T03:41:21.007 回答