Jeswang's Blog

盲目跟随还是独立去做,To be or not to be?

Shell 排序大文件

| Comments

题目:一句 Shell 脚本,使用 2G 内存,排序一个 10G 的文件。

准备工作

首先,我们用 Python 脚本计算一个 10G 的文件最大的整数是多少(因为硬盘的原因就以 10M 为例),10M 得到的结果是 1449607。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# First approache
total = 1024*1024*10
total -= 2
count = 0
for i in range(1, 100000):
    size = (10**i-10**(i-1))*(i+1)
    if total >= size:
        total -= size
        count = i
    else:
        break
print (total/(count+2)) - 1 + 10**count
print "Remain Bytes: ", total%(count+2)

# Second approache
# 只做小数据时验证使用
total = 1024*1024*10
for i in range(0, 10000000):
    total -= len(str(i)) + 1
    if total < 0:
        print i-1
        print "Remain Bytes: ", total+ len(str(i)) + 1
        break

然后,调用 seq 和 shuf(在 OS X 下可以先执行 brew install coreutils 安装软件包,然后使用 shuf)命令生成打乱的文件。

1
2
seq -f '%0.f' 0 1449607 > old_dat
gshuf old_data -o old_data2
  • 如果不放心自己生成文件的大小,可以用 Hex Field 查看一下:

具体 Shell 的编写

由于 sort 命令会把所有传递给它的数字存在内存里排序,所以把所有的内容分为几部分进行排序可以减少 sort 所占用的内存。虽然多扫了几次文件,但是内存可以少占用很多。由于我们最大的数字就是 1449607,还不到 2M 个数字,所以每次处理 1M 的话,分两次就搞定了。

1
2
3
for i in `seq 0 1`;
do awk 'BEGIN{i='$i'}{if($1>=1024*i && $1<1024*(i+1))print $0}' old_data2 | sort -g >> new_data;
done;

最后,比较一下排序出的文件与最初的文件是否相同,相同就说明我们的命令写对了。

1
diff old_data new_data

最后

这还只是一个很粗浅的方法,但是摸索的过程中学到了很多 Shell 的知识。后续可能会找个工具测一下 sort 命令的执行效率,进而给出更准确的答案。

相关链接

- EOF -

Comments