UNIX的sort命令如何对大型文件进行排序?

118

UNIX的sort命令可以像这样对大型文件进行排序:

sort large_file

排序算法是如何实现的?

为什么它不会导致过多的内存消耗?


4
为什么 Stack Overflow 上的每个人都感觉时刻都有必要猜测呢? - anon
你可以对输入进行多次处理 - 你只需要读取所有的输入,将其写入磁盘,然后对磁盘文件进行排序。 - anon
2
@Neil - 从上下文来看,显然他是想对文件的内容进行排序,而不是文件名(对于一个名称来说是没有意义的)。我只是想在不改变上下文太多的情况下改进问题,以便它能得到答案,而不是因为一个简单的错误而被投票否决。 - tvanfosson
@tvanfosson 这确实是一个错误,非常抱歉犯了这个错误。 - yjfuk
http://unix.stackexchange.com/questions/120096/how-to-sort-big-files - Ciro Santilli OurBigBook.com
显示剩余3条评论
8个回答

124

UNIX Sort命令的算法细节显示,Unix Sort使用外部R-Way归并排序算法。这个链接提供了更多详情,但基本上它将输入分成较小的部分(适合内存),然后在最后将每个部分合并在一起。


52

sort 命令将工作数据存储在临时磁盘文件中(通常位于 /tmp 目录下)。


25
使用“-T”命令指定临时目录。 - glenn jackman

12

警告:此脚本每个文件块都会启动一个shell,在处理非常大的文件时,可能会有数百个shell进程。


这是我为此目的编写的脚本。在一台4核处理器的计算机上,它将排序性能提高了100%!

#! /bin/ksh

MAX_LINES_PER_CHUNK=1000000
ORIGINAL_FILE=$1
SORTED_FILE=$2
CHUNK_FILE_PREFIX=$ORIGINAL_FILE.split.
SORTED_CHUNK_FILES=$CHUNK_FILE_PREFIX*.sorted

usage ()
{
     echo Parallel sort
     echo usage: psort file1 file2
     echo Sorts text file file1 and stores the output in file2
     echo Note: file1 will be split in chunks up to $MAX_LINES_PER_CHUNK lines
     echo  and each chunk will be sorted in parallel
}

# test if we have two arguments on the command line
if [ $# != 2 ]
then
    usage
    exit
fi

#Cleanup any lefover files
rm -f $SORTED_CHUNK_FILES > /dev/null
rm -f $CHUNK_FILE_PREFIX* > /dev/null
rm -f $SORTED_FILE

#Splitting $ORIGINAL_FILE into chunks ...
split -l $MAX_LINES_PER_CHUNK $ORIGINAL_FILE $CHUNK_FILE_PREFIX

for file in $CHUNK_FILE_PREFIX*
do
    sort $file > $file.sorted &
done
wait

#Merging chunks to $SORTED_FILE ...
sort -m $SORTED_CHUNK_FILES > $SORTED_FILE

#Cleanup any lefover files
rm -f $SORTED_CHUNK_FILES > /dev/null
rm -f $CHUNK_FILE_PREFIX* > /dev/null

另请参见:使用shell脚本更快地对大文件进行排序


38
从GNU sort版本8.11开始,您可以使用sort --parallel N命令进行排序,其中N为并行处理的线程数。 - jhclark
5
GNU coreutils 8.6 实际上是一个软件包,其中包含了一系列的基本工具和实用程序,旨在提高Linux和其他Unix操作系统的用户体验。 - bdeonovic
1
这个对我很有用。我使用的是8.4版本的sort。直接在文件上使用sort(1.9亿行)没有任何进展。但这个程序只用了不到4分钟就完成了。 - Sunil B
2
这个脚本很危险。在启动了数百个排序进程后,我的Linux机器失去了响应... - Yongwei Wu
1
@WattsInABox 这被称为微妙的炫耀。 - NoName
显示剩余3条评论

12
#!/bin/bash

usage ()
{
    echo Parallel sort
    echo usage: psort file1 file2
    echo Sorts text file file1 and stores the output in file2
}

# test if we have two arguments on the command line
if [ $# != 2 ]
then
    usage
    exit
fi

pv $1 | parallel --pipe --files sort -S512M | parallel -Xj1 sort -S1024M -m {} ';' rm {} > $2

这太棒了。我不知道还有一个并行包!使用上述方法后,排序时间提高了50%以上。谢谢。 - xbsd
我尝试使用comm命令对这些文件进行差异比较,但它给出了一个警告,提示文件未排序。 - ashishb

11

7
仔细查看排序选项以加速性能,并了解其对计算机和问题的影响。Ubuntu上的关键参数包括
  • 临时文件的位置-T directory_name
  • 使用的内存量-S N%(要使用所有内存的N%,越多越好但避免过度订阅导致交换到磁盘。您可以像“-S 80%”这样使用它,使用可用RAM的80%,或者使用“-S 2G”表示2GB RAM。)
提问者问“为什么不使用高内存?”答案来自历史,旧的unix机器很小,缺省内存大小也很小。将其调整为尽可能大的工作负载,可以极大地改善排序性能。将工作目录设置为位于最快设备上并具有足够空间以容纳至少1.25倍正在排序的文件大小的位置。

在一台内存为64GB的计算机上,使用-S 80%尝试对一个2.5GB的文件进行操作时,实际上它确实使用了整个百分比,即使整个文件比这还要小。为什么会这样?即使它没有使用in-place排序,这似乎也是多余的。 - Joseph Garvin
可能 sort -S 在读取文件内容之前就为排序过程预先分配了内存。 - Fred Gannett

-2

如何使用-T选项对大文件进行排序

我需要对一个大文件的第七列进行排序。

我一直在使用:

grep vdd  "file name" | sort -nk 7 |

我遇到了以下错误:
******sort: write failed: /tmp/sort1hc37c: No space left on device******

然后我使用了如下的-T选项,它起作用了:

grep vdda  "file name" | sort -nk 7  -T /dev/null/ |

1
请使用其他示例目录而不是 /dev/null。 - Karl Tarbe

-3

内存不应该是一个问题——排序已经解决了这个问题。如果您想充分利用多核 CPU,我已经在一个小脚本中实现了这些(类似于您可能在网络上找到的一些脚本,但比大多数脚本更简单/更清洁 ;))。

#!/bin/bash
# Usage: psort filename <chunksize> <threads>
# In this example a the file largefile is split into chunks of 20 MB.
# The part are sorted in 4 simultaneous threads before getting merged.
# 
# psort largefile.txt 20m 4    
#
# by h.p.
split -b $2 $1 $1.part
suffix=sorttemp.`date +%s`
nthreads=$3
i=0
for fname in `ls *$1.part*`
do
    let i++
    sort $fname > $fname.$suffix &
    mres=$(($i % $nthreads))
    test "$mres" -eq 0 && wait
done
wait
sort -m *.$suffix 
rm $1.part*

4
有趣的脚本,但它对回答这个问题没有任何帮助。 - Joachim Sauer
5
split -b会按字节进行分割,因此会在任意位置截断行。 - mkm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接