【问题标题】:Command with combined behavior of both `sort -n -u -k` and `uniq -c`具有 `sort -n -u -k` 和 `uniq -c` 组合行为的命令
【发布时间】:2013-11-26 15:25:02
【问题描述】:

我有一个多字段文本文件。我想要一个将sort -n -u -k 和uniq -c 的行为结合起来的命令 - 也就是说,对某个键字段的文件进行排序,并提供在原始行之前或延迟的重复项的数量。目前,我要么对某个键进行排序,然后使用sort -n -u -k 获取重复行数中没有重复的第一行,要么通过提取键字段来计算uniq -c 的重复数。

你能建议一个同时实现这两种行为的命令吗?

文件示例(键列可以是任意指定的):

       4549              1       22656489       63452157           3235           1116            612         532275        6009800         534075        6012488         477375        5995844         533175        6011144        8388615            236
       4549              2       22656489       63452158           3214           1116            613         532275        6009825         534075        6012488         477375        5995831         533175        6011157        8388615            236
       4549              3       22656489       63452159           3193           1116            614         532275        6009850         534075        6012488         477375        5995819         533175        6011169        8388615            236
       4549              4       22656489       63452160           3173           1116            615         532275        6009875         534075        6012488         477375        5995806         533175        6011182        8388615            235
       4549              5       22656489       63452161           3152           1116            616         532275        6009900         534075        6012488         477375        5995794         533175        6011194        8388615            235
       4549              6       22656489       63452162           3131           1116            617         532275        6009925         534075        6012488         477375        5995781         533175        6011207        8388615            235
       4549              7       22656489       63452163           3111           1116            618         532275        6009950         534075        6012488         477375        5995769         533175        6011219        8388615            235
       4549              8       22656489       63452164           3091           1116            619         532275        6009975         534075        6012488         477375        5995756         533175        6011232        8388615            234
       4549              9       22656489       63452165           3070           1116            620         532275        6010000         534075        6012488         477375        5995744         533175        6011244        8388615            234
       4549             10       22656489       63452166           3050           1116            621         532275        6010025         534075        6012488         477375        5995731         533175        6011257        8388615            234
       4549             11       22656489       63452167           3030           1116            622         532275        6010050         534075        6012488         477375        5995719         533175        6011269        8388615            234

【问题讨论】:

  • 管道 (sort -n -k | uniq -c) 是否不符合您的需求?
  • 不,因为uniq -c 不尊重某个关键字段的唯一性,而是将整行与其他行进行比较。
  • uniq 确实具有有限 忽略不需要的字段的能力(-f 和-s 选项)。如果这还不够,您可以(如果它满足您的其他要求)在sort 和uniq 之间放置cut 或awk 命令,以将字段重新排序为uniq 可以处理的形式。跨度>
  • 这就是问题所在——我需要sort 和uniq 这两种想要的行为——也就是说,保持整行不变,但使用特定字段作为键 and i> 计算该键上的重复次数。
  • 我认为如果你能更具体一些会很有帮助:你的输入数据是什么样的,有多少字段,字段分隔符是什么,你想对哪个字段进行排序等等。 ?

标签: linux sorting command-line uniq


【解决方案1】:

使用decorate-sort-undecorate,您可以将要作为处理基础的字段附加到数据中,进行处理并删除额外的字段。例如,对字段 17 和 5 进行排序:

awk '{print $0 OFS $17 OFS $5}' test_s  | sort -n -k18 -k19  | uniq -c -f17 | awk '{NF=18;print}'

你先追加关键字段,然后在上面追加sort和uniq,然后只保留uniq加上的计数和原来的字段。

【讨论】:

    【解决方案2】:

    据我目前的理解,您希望指定一个或多个列用作键,并获得一个结果,每个输出行显示该键的多重性。在这种情况下,假设您的数据在一个名为“data”的文件中,我们希望第 17 列作为键:

    $ awk '{print $17}' data  | sort -n | uniq -c
      4 234
      4 235
      3 236
    

    因此,236 的值在您的测试数据中总共出现 3 次出现在第 17 列中。或者,假设您希望第 6、8、1 和 3 列作为键(并按此顺序):

    $ awk '{print $6,$8,$1,$3}' data  | sort -n | uniq -c
     11 1116 532275 4549 22656489
    

    对于这个键,所有 11 行都是重复的。

    这种方法分为三个步骤。首先,我们让awk 按您想要的顺序选择您想要的列。其次,sort -n 在键上按数字对它们进行排序。最后,uniq 计算重复项。

    更新:假设,如上所述,我们希望使用第 6、8、1 和 3 列作为键,但根据您的评论,我们希望保留原始行之一。在这种情况下,我们指示 awk 将原来的 17 列放在键之前,我们告诉 sort 对键(第 18 列以上)进行排序,然后我们指示 uniq 忽略前 17 列:

    awk '{print $0,$6,$8,$1,$3}' data  | sort -k18 -n | uniq -f 17 -c
    

    对于您的示例数据,这会导致:

         11        4549             10       22656489       63452166           3050           1116            621         532275        6010025         534075        6012488         477375        5995731         533175        6011257        8388615            234 1116 532275 4549 22656489
    

    如果您只想打印原始的 17 列,那么我们可以使用 perl 仅显示前 17 列并裁剪掉键:

    awk '{print $0,$6,$8,$1,$3}' data  | sort -k18 -n | uniq -f 17 -c | perl -nle '@a=split;print join " ", @a[0..17]'
    

    导致:

    11 4549 10 22656489 63452166 3050 1116 621 532275 6010025 534075 6012488 477375 5995731 533175 6011257 8388615 234
    

    【讨论】:

    • 您的理解几乎是正确的,只是我不想丢失原始行之一的信息。在您的回答中,除了原始行的键值之外的所有内容都丢失了,但我想根据键计算重复的行,保留代表整个重复组的行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2014-03-02
    相关资源
    最近更新 更多