【问题标题】:How do I sort lines by number of appearances UNIX?如何按 UNIX 的出现次数对行进行排序?
【发布时间】:2018-03-19 05:28:21
【问题描述】:

我想按出现次数对输入进行排序。但是我不想删除唯一或非唯一行。例如,如果我得到以下输入:

Not unique
This line is unique
Not unique
Also not unique
Also unique
Also not unique
Not unique

我正在寻找一组可以输出以下内容的流水线命令:

This line is unique
Also unique
Also not unique
Also not unique
Not unique
Not unique
Not unique

感谢您提供的任何帮助,我一直在尝试使用 unique 和 sort 的不同组合,但无法弄清楚,解决方案最好是单行。

更新:感谢所有回复的人,尤其是@batMan,他的答案正是我正在寻找的我熟悉的命令。

我仍在尝试学习如何通过管道和使用多个命令来完成看似简单的任务,那么我是否可以调整他的答案以使用 2 列?例如,如果原始输入是:

Notunique dog 
Thislineisunique cat 
Notunique parrot 
Alsonotunique monkey 
Alsounique zebra 
Alsonotunique beaver 
Notunique dragon

我希望输出按第一列排序,如下所示:

Thislineisunique cat 
Alsounique zebra 
Alsonotunique monkey 
Alsonotunique beaver 
Notunique dog 
Notunique parrot 
Notunique dragon

感谢大家提前提供的帮助!

【问题讨论】:

  • 你能展示一下到目前为止你尝试了什么吗?我会使用一个简短的 Python 脚本,使用 collections.Counter 可能会非常短,但这不适用于纯 shell 解决方案。

标签: algorithm shell sorting awk uniq


【解决方案1】:

awk 最适合您更新的问题。

$ awk '{file[$0]++; count[$1]++; max_count= count[$1]>max_count?count[$1]:max_count;} END{ k=1; for(n=1; n<=max_count; n++){ for(i in count) if(count[i]==n) ordered[k++]=i} for(j in ordered) for( line in file) if (line~ordered[j]) print line; }' file

Alsounique zebra
Thislineisunique cat
Alsonotunique beaver
Alsonotunique monkey
Notunique parrot
Notunique dog
Notunique dragon

说明:

第 1 部分:

{file[$0]++; count[$1]++; max_count= count[$1]&gt;max_count?count[$1]:max_count;}:

我们将您的输入文件存储在file 数组中; count 数组跟踪每个唯一的第一个字段的计数,您希望根据这些字段对文件进行排序。 max_count 跟踪最大计数。

第 2 部分: 一旦 awk 完成读取文件,count 的内容将如下所示:(keys, values)

Alsounique 1
Notunique 3
Thislineisunique 1
Alsonotunique 2

现在我们的目标是按值对这些键进行排序,如下所示。这是我们的关键步骤,因为对于下面输出中的每个字段/键/列 1,我们将遍历 file 数组并打印包含这些键的行,它将为我们提供最终所需的输出。

Alsounique 
Thislineisunique 
Alsonotunique 
Notunique 

下面的循环执行以sorted by values 方式将count 数组的内容存储到另一个名为ordered 的数组中的操作。 ordered 的内容将与上面显示的输出相同。

for(n=1; n<=max_count; n++)
    { 
        for(i in count) 
            if(count[i]==n) 
            ordered[k++]=i
    } 

最后一步:即遍历file数组并按照存储在ordered数组中的字段顺序打印行。

for(field in ordered) 
    for( line in file) 
        if (line~ordered[field]) 
            print line; 
    }

解决方案 2 :
另一种可能的解决方案是使用 sort、uniq 和 awk/cut。但如果您的输入文件非常大,我不建议使用此方法,因为多个管道调用多个进程会减慢整个操作。

$ cut -d ' ' -f1 file | sort | uniq -c | sort -n | awk 'FNR==NR{ordered[i++]=$2; next} {file[$0]++;} END{for(j in ordered) for( line in file) if (line~ordered[j]) print line;} ' - file
Alsounique zebra
Thislineisunique cat
Alsonotunique beaver
Alsonotunique monkey
Notunique parrot
Notunique dog
Notunique dragon

以前的解决方案(在 OP 编辑​​问题之前)

这可以使用sort、uniq 和awk 来完成,如下所示:

$ uniq -c <(sort f1) | sort -n | awk '{ for (i=1; i<$1; i++){print}}1'
      1 Also unique
      1 This line is unique
      2 Also not unique
      2 Also not unique
      3 Not unique
      3 Not unique
      3 Not unique

【讨论】:

  • 非常感谢您,它完全符合我的要求!我仍在尝试学习如何为看似简单的任务流水线化和使用多个命令,那么我是否可以将其调整为与 2 列一起使用?例如,如果原始输入是 Notunique 1 Thislineisunique 2 Notunique 3 Alsonotunique 4 Alsounique 5 Alsonotunique 6 Not unique 7 我希望输出按第一列排序 Thislineisunique 2 Alsounique 5 Alsonotunique 4 Alsonotunique 6 Notunique 1 Notunique 3 Notunique 7其中数字仅代表任何文本
  • 我编辑了原始帖子,所以之前的评论格式更好,再次感谢您!
  • 第一列在您的方法中是多余的
  • @trysofter:检查更新后的解决方案,了解您更新后的问题。如果您有任何问题,请告诉我。
  • 感谢您帮助我学习如何使用这些命令以及您的深入解释!但是,我尝试仅使用您的 awk 解决方案,并将键正确地组合在一起,但是输出不像未更新的问题那样基于第一列的上升频率。对于给定输入,我的机器上的输出是: Notunique dog Notunique dragon Notunique parrot Alsounique zebra Thislineisunique cat Alsonotunique beaver Alsonotunique monkey 解决方案 2 有效,但我现在想知道如何修复 awk 函数也可以工作,再次感谢您的帮助!
【解决方案2】:

我会使用awk 来计算每行出现的次数,然后将它们打印出来(按频率预先确定)并使用sort -n 进行数字排序:

awk 'FNR==NR{freq[$0]++; next} {print freq[$0],$0}' data.txt data.txt | sort -n

样本输出

1 Also unique
1 This line is unique
2 Also not unique
2 Also not unique
3 Not unique
3 Not unique
3 Not unique

这真的是一个 Schwartzian 变换。如果要丢弃前导频率列,只需在命令末尾添加| cut -d ' ' -f 2-即可。

【讨论】:

    【解决方案3】:

    uniq + sort + grep 解决方案:

    扩展inputfile内容:

    Not unique
    This line is unique
    Not unique
    Also not unique
    Also unique
    Also not unique
    Not unique
    Also not unique
    Also not unique
    

    预先对初始文件进行排序:

    sort inputfile > /tmp/sorted
    

    uniq -u /tmp/sorted; uniq -dc /tmp/sorted | sort -n | cut -d' ' -f8- \
       | while read -r l; do grep -x "$l" /tmp/sorted; done
    

    输出:

    Also unique
    This line is unique
    Not unique
    Not unique
    Not unique
    Also not unique
    Also not unique
    Also not unique
    Also not unique
    

    ---------

    您也可以将整个作业包含在bash 脚本中:

    #!/bash/bash
    
    sort "$1" > /tmp/sorted   # $1 - the 1st argument (filename)
    uniq -u /tmp/sorted
    
    while read -r l; do
        grep -x "$l" /tmp/sorted
    done < <(uniq -dc /tmp/sorted | sort -n | cut -d' ' -f8-)
    

    【讨论】:

    • 这不按出现次数排序,它只是将唯一行(排序)放在首位,非唯一行按字母顺序排序,而不是按频率排序。如果输入中有几行 Also not unique,它应该显示在输出的末尾,但它不会用于此解决方案。
    • 只需将其用作您的输入文件,每个字符单独一行:A A B B B B C C C。显然,按频率排序,这要么必须成为A A C C C B B B B,要么降序排序,B B B B C C C A A,但它将是未修改的输入。 uniq 不会重新排列它的输入,只是过滤它。
    猜你喜欢
    • 1970-01-01
    • 2017-02-21
    • 2019-10-25
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    相关资源
    最近更新 更多