如何按出现次数排序行?UNIX

时间:2017-10-07 15:49:40

标签: algorithm shell sorting awk uniq

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

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

感谢您提供的任何帮助,我一直在努力使用独特和排序的不同组合,但无法弄明白,解决方案最好是单线。

更新:感谢所有回复的人,尤其是@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

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

3 个答案:

答案 0 :(得分: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]>max_count?count[$1]:max_count;}

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

<强>部分-2: awk完成读取文件后,count的内容如下:(键,值)

Alsounique 1
Notunique 3
Thislineisunique 1
Alsonotunique 2

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

Alsounique 
Thislineisunique 
Alsonotunique 
Notunique 

下面的循环执行以count方式将ordered数组的内容存储在名为sorted by values的另一个数组中的操作。 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
另一种可能的解决方案是使用排序 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之前编辑问题)

可以使用sortuniqawk完成此操作:

$ 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

答案 1 :(得分:0)

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-)

答案 2 :(得分:0)

我会使用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

这真是一个施瓦茨变换。如果要丢弃前导频率列,只需将| cut -d ' ' -f 2-添加到命令的末尾。