问题描述
这是我输入的片段:
DGD3 SOL10
DGD53 SOL15
DGD100 SOL15
DGD92 SOL20
DGD41 SOL22
DGD62 SOL35
DGD13 SOL40
DGD13 SOL40
我的预期输出
DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40
在我的数据中,我有时会重复 SOL(不超过两次重复,而不是例如文件中某些 SOL 的三倍,但仅重复)。 SOL 在我的第二列中($2)。因此,当我找到重复的 SOL($2)时,我需要一个打印整行(DGD 和 SOL)的程序。你能帮我吗?
解决方法
以 awkish 风格添加另一种方式,在第一次读取 Input_file 时获取所有值计数并在第二次读取时根据它们的计数打印所有值。公平警告,这可能不如其他 2 个解决方案快,但从理解目的来看应该很简单。
awk '
FNR==NR{
count[$2]++
next
}
(count[$2]>1)
' Input_file Input_file
,
使用您的示例(按第二个字段排序),您可以执行以下操作:
$ awk 'l2==$2{print ll; print; next}
{ll=$0; l2=$2}' file
打印:
DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40
这类似于 Unix uniq
过滤器,它只打印相邻的重复项。
如果文件中的重复项是随机的,您可以先排序:
$ awk 'l2==$2{print ll; print; next}
{ll=$0; l2=$2}' <(sort -k 2 file)
或者,对文件进行两次传递:
$ awk 'FNR==NR{cnt[$2]++; next} cnt[$2]>1' file file
或者,仅识别 2 个或更多的 SOL 标签,您可以:
$ awk '++cnt[$2]==2' file
您可以使用相同的方法生成 grep
或 sed
的命令代码,以从未排序的文件中打印:
$ sed -n -f <(awk '++cnt[$2]==2 {printf "/[[:space:]]%s$/p\n",$2}' file) file
所以选择是:
- 使用更多内存(通过将整个文件缓存在以
$2
值键控的内存中),或 - 先排序,或者
- 遍历文件两次。
您可以使用此 awk
,它将打印重复不一定是相邻的:
awk '$2 in map {print map[$2] ORS $0} {map[$2] = $0}' file
DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40
,
如果您的文件在第二个字段中排序,uniq
是为该任务设计的,具有正确的选项。
$ uniq -f1 -D file
DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40
跳过第一个字段,打印所有重复项...
,另一个 awk。单次运行,不需要对文件进行排序,如果第二个字段的实例超过 2 个,则可以正常工作。在最坏的情况下,它会散列内存中的完整文件并且不产生任何输出:
$ awk '{
if(!c[$2]++) # if first instance of $2
a[$2]=$0 # store it
else {
if(c[$2]==2) { # if second instance
print a[$2] # print previous
delete a[$2] # no need to waste my memory any more
}
print # after first instance of $2 we always print current
}
}' file
输出:
DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40