关于排序:gnu-sort – 当说合并选项“不排序”时手动意味着什么

gnu-sort - what does manual mean when it says merge option does “not sort”

我试图对一个太大而无法放入内存的文件进行排序。选项-m下的gnu排序的人声明:merge already sorted files; do not sort。我正在努力理解这一点的含义,以确保排序完成我想要的。这篇文章(在大型数据集的pandas中排序)建议将gnu split和gnu sort组合起来完成这样的任务,首先将文件分成适合内存的小块,分别对每个文件进行排序,然后重新组合。到目前为止,我的实验似乎表明这个程序确实有效。尽管如此,我对手册中合并选项的描述感到困扰,该选项表明它没有排序。出于我的目的,有必要对大文件进行完全排序,而不仅仅是已经本地排序的较小片段的串联。虽然我已经在小例子上测试过程并且似乎有效,但是手册让我对将其应用到我的实际情况缺乏信心,因为我担心在不再可行验证gnu的情况下是否会出现意外行为排序按照我的意图运作。

要提供MWE,请考虑我要排序的此选项卡分隔文件:

1
2
3
4
3   4
2   5
3   1
1   3

我尝试了以下操作:

1
2
3
4
5
6
7
8
SortDir="/Users/aireties/Desktop/Sort_Experiments"
## sort document as a whole (in practice, this would be infeasible due to document size)
sort --field-separator=$'\t' -k 1,1 -k 2,2"$SortDir/To_Be_Sorted.txt" -o"$SortDir/Sorted_as_Whole.txt"  ## sort first by the first column values, then by the second

1   3
2   5
3   1
3   4

这是在立即对整个文件进行排序时的"正确"解决方案(在我的实际用例中这是不可行的)。

如果我试图将文件分成几块然后立即使用-m选项,我得到一个不正确的结果:

1
2
3
4
5
6
7
8
9
10
11
## Break file into pieces
MaxLines=2
mkdir"$SortDir/Pieces/"
split -l $MaxLines"$SortDir/To_Be_Sorted.txt""$SortDir/Pieces/"
## Try merge sort on pieces without first sorting them
sort -m --field-separator=$'\t' -k 1,1 -k 2,2"$SortDir/Pieces/"* -o"$SortDir/Sorted_in_Pieces1.txt"

3   1
1   3
3   4
2   5

它出现的情况是,gnu sort只考虑了两个单独的部分,并根据彼此的第一个值对它们进行了排序。因此,它已将第二件放在这件成品中,但没有进行其他分类。

或者,如果我按照这里提倡的程序(在大熊猫中为大型数据集排序),即首先对各个部分进行排序然后合并,我似乎得到了正确的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for file in"$SortDir/Pieces/"*  ## sorts all text files in pwd
do
  sort --field-separator=$'\t' -k 1,1 -k 2,2"$file" -o"$file"
done    

sort -m --field-separator=$'\t' -k 1,1 -k 2,2"$SortDir/Pieces/"* -o"$SortDir/Sorted_in_Pieces2.txt"    

1   3
2   5
3   1
3   4


cmp --silent"$SortDir/Sorted_in_Pieces1.txt""$SortDir/Sorted_as_Whole.txt" || echo"files are different"
# file are different
cmp --silent"$SortDir/Sorted_in_Pieces2.txt""$SortDir/Sorted_as_Whole.txt" || echo"files are different"

对我来说,关键点在于,如果片段文件很大,那么仍然需要进行大量计算才能将它们合并到一个正确排序的单个文件中。因此,我发现我很难理解如何将这种非平凡的排序描述为声称它"不排序"的操作的结果。

任何人都可以告诉我为什么手册会被这样说?为什么以及如何确信gnu sort在使用合并选项时能够可靠地执行它所声称的内容?手册文本是否暗示某些情况下该程序无法达到预期效果?


Gnu排序(至少是我查看源代码的版本),将对内存中的文件块进行排序,并创建一组临时文件(每个块一个临时文件)。它还在内存排序阶段使用多线程(命令行参数可以设置要使用的最大线程数)。在创建所有临时文件之后,它会对临时文件执行16路合并(除非您覆盖它),直到它生成单个排序文件。

这里的要点是您不必先将文件拆分为单独的文件,因为gnu sort会自动处理大文件,根据需要创建排序的临时文件以合并到单个排序文件中。

-m选项适用于要合并多个已排序文件的特殊情况。


-m只是简单地将文件合并在一起,就像mergesort的merge操作一样。它需要根据相同的顺序对两个文件进行排序。

因此,为了对非常大的文件进行排序,您所做的工作确实有效:将其拆分为几个较小的文件,在本地对它们进行排序。此时,如果你只是将每个文件追加到另一个文件,你最终会得到像0 1 2 3 ... 0 1 2 3这样的东西

-m选项确实合并它们。

例如,那些:

1
2
3
4
5
6
7
8
9
10
11
12
13
a  b
1  3
2  2
3  1

sort -m a b
# 1 2 3 3 2 1
sort -m a a
# 1 1 2 2 3 3
sort -m b b
# 3 2 1 3 2 1
sort -r -m b a
# 3 2 1 1 2 3