mkdir tmp
sort -u *.txt -T tmp/ -o output.txt
只有几十 GB 大小的文件需要排序。
问题是几分钟后排序会出现分段错误。
操作系统是最新的 Scientific Linux 6.6。
问题:如何对文件进行“排序 -u”? Sort 无法处理较大的文件?.. 当发生段错误时,RAM 未满一半.. 只有一个核心处于 100%
答案1
过去,我不得不对太大的文件进行排序sort
。我认为这也是您的问题,但如果您提供更多信息,也许我们可以更好地诊断您的问题。
grep
我的问题的解决方案是用预处理器来分解文件。查看您的数据以了解团块的位置。我假设它在字母数字空间中分布得很好,但稍后我将讨论如何处理簇。
for char1 in other {0..9} {a..z}; do
out="/tmp/sort.$char1"
echo "Extracting lines starting with '$char1'"
if [ "$char1" = "other" ]; then char1='[^a-z0-9]'; fi
grep -i "^$char1" *.txt > "$out"
sort -u "$out" >> output.txt || break
done
(这使用了 bashism。为了避免它,请明确命名 37 个字符中的每一个,例如for char1 in other 0 1 2 3 4 5 6 7 8 9 0 a b c d e f ...
)
团块:由于数据太多,这些循环调用中的一些可能sort
会出现段错误。只需修改迭代以将其分解为多个部分即可。这可能很简单,只需删除 grep 的-i
标志并调出每个大写字母(不要忘记将 改为other
)[^a-zA-Z0-9]
,或者可能需要深入研究数据。如果这是软件包列表,则可能有太多以“lib”开头的行,因此迭代/tmp/sort.l
将失败。|| break
此循环的一部分将在此时停止处理,因此您可以修复它并从上次中断的地方继续。按照“lib”示例,您可能希望使用类似以下内容继续:
for char1 in 'l[a-h]' 'lia' lib{a..z} lib{0..9} 'li[c-z]' 'l[j-z]' {m..z}; do
...
这会将l
列表分为 lib* 部分之前和之后的部分。它有点难看,但应该可以。只需注意所需的顺序即可保存它。
答案2
另一种可能性是分别对每个文件进行排序,然后合并它们:
for f in *txt; do
sort -u "$f" -T tmp/ > "$f".sorted
done
sort -mu *sorted
该-m
选项会sort
合并已排序的文件,而不是尝试对它们进行排序。这应该会导致内存使用量低得多,并且应该避免段错误。
答案3
结合不同的答案:当您想对文件进行分段排序时,请尝试使用 split:
LARGETMP=/var/tmp
mkdir ${LARGETMP}
N_LINES=100000 # Adjust when to still too large or too small
split --lines=${N_LINES} bigfile splitted_
for small in splitted*; do
sort -u -T ${LARGETMP} ${small} > sorted_${small}
rm ${small}
done
echo "Done with sorting the splitted files, now concate the stuff"
sort -um -T ${LARGETMP} sorted_* > bigfile.sorted
编辑:正如 @ua2b 评论的那样,按大小分割主要会在行中间分割。
(当文件没有换行时,整个排序的想法有点奇怪)。
答案4
我在OpenBSD上找到了一种方法:
http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/sort.1?query=sort&sec=1
-H
Use a merge sort instead of a radix sort. This option should be used for files larger than 60MB.
但这不是一个完全好的解决方案,因为它占用了太多空间... x>100 GByte 还不够。