awk统计唯一出现次数并打印其他列

awk统计唯一出现次数并打印其他列,awk,uniq,Awk,Uniq,我有以下代码: awk '{h[$1]++}; END { for(k in h) print k, h[k]}' ${infile} >> ${outfile2} 这就是我想要的:打印出唯一值,然后计算这些唯一值出现的次数。现在,我想打印出第2列和第3列以及每个唯一值。出于某种原因,以下各项似乎不起作用: awk '{h[$1]++}; END { for(k in h) print k, $2, $3, h[k]}' ${infile} >> ${outfile2}

我有以下代码:

awk '{h[$1]++}; END { for(k in h) print k, h[k]}' ${infile} >> ${outfile2}
这就是我想要的:打印出唯一值,然后计算这些唯一值出现的次数。现在,我想打印出第2列和第3列以及每个唯一值。出于某种原因,以下各项似乎不起作用:

awk '{h[$1]++}; END { for(k in h) print k, $2, $3, h[k]}' ${infile} >> ${outfile2}
awk '{h[$1]++}; END { for(k in h) print k, h[$2], h[$3], h[k]}' ${infile} >> ${outfile2}
第一个代码打印最后一个索引的第2列和第3列,而第二个代码只打印k和h[k]

${infle}看起来像:

20600        33.8318 -111.9286       -1     0.00        0
20600        33.8318 -111.9286       -1     0.00        0
30900        33.3979 -111.8140       -1     0.00        0
29400        33.9455 -113.5430       -1     0.00        0
30600        33.4461 -111.7876       -1     0.00        0
20600        33.8318 -111.9286       -1     0.00        0
30900        33.3979 -111.8140       -1     0.00        0
30600        33.4461 -111.7876       -1     0.00        0
所需的输出将是:

20600, 33.8318, -111.9286, 3
30900, 33.3979, -111.8140, 2
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
是一个非常方便的工具,用于处理文件中的列数据组,这使得这项工作变得非常简单

假设文件使用选项卡分隔列,如下所示:

$ datamash -s --output-delimiter=, -g 1,2,3 count 3 < input.tsv
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2
如果您希望对这个输出进行排序而不是随机排序,如果使用GNU awk,请在BEGIN块中添加一个PROCINFO[sorted_in]=@ind_str_asc,或者通过sort管道输出

您还可以通过管道化一系列实用程序(包括awk和uniq)来获得相同的效果:

$ sort -k1,3n input.tsv | cut -f1-3 | uniq -c | awk -v OFS=, '{ print $2, $3, $4, $1 }' 
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2

您很接近,可以在awk中完成这一切,但是如果您要基于字段1存储计数,并且在结束输出时还可以使用字段2和字段3,那么您还需要将字段2和3存储在由字段1索引的数组中,或者保存计数的任何字段中。例如,您可以执行以下操作:

awk -v OFS=', ' '
    { h[$1]++; i[$1]=$2; j[$1]=$3 }
    END { 
        for (a in h)
            print a, i[a], j[a], h[a]
        }
' infile
其中,h[$1]保存字段1索引具有字段1的数组的次数计数。i[$1]=$2捕获由字段1索引的字段2,然后j[$1]=$3捕获由字段1索引的字段3

然后在END中,只需输出字段1A,h的索引,i[a]字段2,j[a]字段3,最后输出字段1的次数计数

示例使用/输出

使用您的示例数据,您只需复制/鼠标中键将代码粘贴到具有正确文件名的终端,例如

$ awk -v OFS=', ' '
>     { h[$1]++; i[$1]=$2; j[$1]=$3 }
>     END {
>         for (a in h)
>             print a, i[a], j[a], h[a]
>         }
> ' infile
20600, 33.8318, -111.9286, 3
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
30900, 33.3979, -111.8140, 2
它提供所需的输出。如果需要按照显示的输出顺序保留记录的顺序,可以使用字符串连接将字段1、2和3分组为数组的索引,然后输出数组和索引,例如

$ awk '{a[$1", "$2", "$3]++}END{for(i in a) print i ", " a[i]}' infile
20600, 33.8318, -111.9286, 3
30600, 33.4461, -111.7876, 2
29400, 33.9455, -113.5430, 1
30900, 33.3979, -111.8140, 2

请仔细查看,如果您还有其他问题,请告诉我。

您必须存储一行的全部值,以便在结束块内打印出来$2和$3将仅来自读取的最后一行输入,但您的h[]数组将有许多条目。在我看来,您需要另一个数组,这样您就可以从uniq列表中引用正确的NR,但现在没有时间测试它。祝你好运,谢谢。我添加了一个分组以保留输出顺序,这做了同样的事情,但在使用索引串联时有点典型。
$ awk '{a[$1", "$2", "$3]++}END{for(i in a) print i ", " a[i]}' infile
20600, 33.8318, -111.9286, 3
30600, 33.4461, -111.7876, 2
29400, 33.9455, -113.5430, 1
30900, 33.3979, -111.8140, 2