希望只打印具有重复第一个字段的行。例如来自如下所示的数据:
1 abcd
1 efgh
2 ijkl
3 mnop
4 qrst
4 uvwx
应该打印出来:
1 abcd
1 efgh
4 qrst
4 uvwx
(仅供参考 - 我的数据中的第一个字段并不总是 1 个字符)
awk 'FNR==NR{a[$1]++;next}(a[$1] > 1)' ./infile ./infile
是的,你给它两次输入相同的文件。由于您不提前知道当前记录是否为 uniq,因此您基于$1
第一遍构建一个数组,然后仅输出$1
在第二遍中多次看到的记录。
我敢肯定有一些方法可以只通过文件一次,但我怀疑它们会像“干净”一样
FNR==NR
awk
:这仅在读取第一个文件时才成立。它本质上是测试看到的记录总数 (NR) 与当前文件中的输入记录 (FNR)。a[$1]++
: 构建一个关联数组,其中谁的键是第一个字段 ( $1
),并且每次看到谁的值都会增加一个。next
:如果达到这一点,则忽略脚本的其余部分,从新的输入记录重新开始(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 代码来做你想做的事,假设输入已经按它的第一个字段分组(就像uniq
也需要):
BEGIN {f = ""; l = ""}
{
if ($1 == f) {
if (l != "") {
print l
l = ""
}
print $0
} else {
f = $1
l = $0
}
}
在此代码中,f
字段 1 的前一个值l
是组的第一行(如果已经打印出来,则为空)。
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
}
假设您在问题中显示的有序输入:
awk '$1 == prev {if (prevline) print prevline; print $0; prevline=""; next} {prev = $1; prevline=$0}' inputfile
该文件只需读取一次。
如果你可以使用 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