命令行的替代方法“sort | uniq -c | sort -n”

时间:2014-02-04 19:02:53

标签: perl shell sorting awk count

我使用sort | uniq -c | sort -n多年,但今天它失败了,因为我的输入文件是10 GB而我的/tmp是1 GB宽:

  

sort: write failed: /tmp/sortmIGbL: No space left on device

因此,我正在寻找日常使用的有效替代方案:

    可以使用
  • awk,但没有排序的关联数组

  • perl似乎是一个不错的选择,但10-years-old solution from perlmonks.org似乎不起作用

    no warnings;
    $^W=0;
    open my $in, $ARGV[0] or die "Couldn't open $ARGV[0]:$!";
    my ($buffer, %h) = ''; keys %h = 1024*500;
    while (sysread($in, $buffer, 16384, length $buffer)) {
        $h{$1}++ while $buffer =~ m[^(?:.+?\|){9}([^|]+)\|]mg;
        $buffer = substr($buffer, rindex($buffer, "\n"));
    }
    print scalar keys %h;
    

如何在非常大的文件上获得与sort | uniq -c | sort -nr | head相同的结果?

  • 因为我使用的是Linux / Cygwin / Solaris / * BSD / ...我对任何想法都持开放态度(便携式或非便携式)
  • 您可以自由使用所需的脚本语言(awk / perl / ...)

输入示例

a
BB
ccccc
dddddddd
a
BB
a

可能的输出之一

    3 a
    2 BB
    1 dddddddd
    1 ccccc

3 个答案:

答案 0 :(得分:5)

您的命令链中的第一个sort是使用所有资源的命令。通过获取首先的唯一行,然后排序:

来减少问题集
perl -ne '
    $count{$_}++;
    END {
        print "$count{$_} $_" for sort {
            $count{$b} <=> $count{$a} || $b cmp $a
        } keys %count
    }
' input.txt

你有66,000个7字节的唯一行,因此对于每个scalars = 3,696,000字节的密钥,散列键占用的内存将是66,000 * 56字节。这不包括哈希的计数和开销,但毫无疑问,这种方法很容易做到。

答案 1 :(得分:3)

排序不是顺序操作,例如你不能只读取10条记录,对它们进行排序,转发它们,然后再记录10条记录。因此,如果您想要对10GB数据进行排序

  • 需要大量内存,例如方式超过10GB
  • 需要大量磁盘空间(至少10GB)或就地排序,例如在文件中(这将适用于固定大小的记录,但对于可变大小的记录将是一场噩梦)
  • 需要一种更智能的方法解决您的问题(例如,如果记录大小为1MB,但只有10个字节与排序相关,您可以通过智能算法更快地使用更少的内存)
BTW,您是否尝试设置TMPDIR,以便排序不使用/ tmp但/ var / tmp或任何其他具有更多磁盘空间的目录?或者你的排序可能有一个-T选项来指定tempdir。

答案 2 :(得分:3)

使用GNU awk进行排序关联数组:

$ gawk '
    BEGIN{ PROCINFO["sorted_in"] = "@val_num_desc" }
    { a[$0]++ }
    END { for (i in a) print a[i], i }
' file
3 a
2 BB
1 dddddddd
1 ccccc

不知道它是否能够有效地为您的大型数据集工作,只是在他的问题下方的OPs评论中显示一个awk排序的关联数组。