在Linux shell中进行排序和去重

56

以下两个命令有什么区别?

sort -u FILE

sort FILE | uniq

当你运行它们时,你看到了什么?你尝试收集不同大小文件的时间差异了吗?你可以运行一些实验并将结果发布为问题的一部分。 - S.Lott
我想知道是否有一种特殊情况,两个命令的行为会有所不同,在正常执行时它们都会产生相同的结果。 - yassin
3
“sort -u”和“sort | uniq”有什么区别? - mtk
@mtk:U&L上的问答基本上是这个问题的副本,但是是在几年之后提出的。答案中的历史评论很有趣。-u选项在UNIX第七版的sort命令中(大约是1979年)就已经存在了,因此所涉及的古代历史确实非常久远。 - Jonathan Leffler
@Jonathan 嗯,我发布它的原因与历史评论有趣相同 :) 另外它还有一些时间实验的说明。 - mtk
6个回答

91

使用sort -u比使用sort | uniq的I/O要少,但最终结果相同。特别是如果文件足够大,sort需要创建中间文件,那么sort -u可能会使用稍微较少或稍微较小的中间文件,因为在排序每个集合时可以消除重复项。如果数据高度重复,则可能有益;如果实际上很少重复,那么这不会有太大的区别(与管道的一级性能效果相比,肯定是二级性能效果)。

请注意,有时候使用管道是适当的。例如:

sort FILE | uniq -c | sort -n

这将按照文件中每行出现次数的顺序对文件进行排序,重复出现最多的行将出现在最后。(我不会感到惊讶,如果发现这种组合,在Unix或POSIX上是习惯用法,可以通过GNU sort命令压缩成一个复杂的排序命令。)

有时候不使用管道是很重要的。例如:

sort -u -o FILE FILE

这会“原地”排序文件;也就是说,输出文件由-o FILE指定,并且此操作是安全的(在写入输出之前,先读取该文件)。


感谢您提供完整的答案! - yassin
GNU Sort 没有一种方法可以完成 sort | uniq -c | sort -n 的所有操作,我也没有找到其他有效的工具来实现它。看起来编写这样一个工具是值得的。 - mc0e

11

有一点小区别:返回值。

问题在于,除非设置了shopt -o pipefail,否则管道命令的返回值将是最后一个命令的返回值。而uniq总是返回零(成功)。尝试检查退出代码,你会看到类似这样的内容(此处未设置pipefail):

pavel@lonely ~ $ sort -u file_that_doesnt_exist ; echo $?
sort: open failed: file_that_doesnt_exist: No such file or directory
2
pavel@lonely ~ $ sort file_that_doesnt_exist | uniq ; echo $?
sort: open failed: file_that_doesnt_exist: No such file or directory
0

除此之外,这些命令是等效的。


9

注意!虽然"sort -u"和"sort | uniq"是等效的,但是任何对sort的附加选项都可能破坏它们之间的等价性。这里有一个来自coreutils手册的例子:

例如,“sort -n -u”只检查初始数字字符串的值以检查唯一性,而“sort -n | uniq”则检查整行。

同样地,如果你按关键字段进行排序,sort使用的唯一性测试就不再必须检查整行了。在过去被这个问题困扰过后,现在我倾向于在编写Bash脚本时使用"sort | uniq"。我宁愿有更高的I/O开销,也不想冒着别人不知道添加额外的sort参数会导致的问题风险。


7

3

我曾在一些服务器上工作,其中sort命令不支持“-u”选项。在这种情况下,我们需要使用

sort xyz | uniq

2
您能否具体说明一下是哪些服务器、使用的操作系统版本以及大致时间?第七版UNIX™中的sort支持-u,这是UNIX的第一个广泛使用的版本,因此所有其他版本(System III、System V、BSD等)都倾向于遵循它,所以我会非常惊讶地发现一个类Unix系统不支持-u - Jonathan Leffler

2

没有区别,它们会产生相同的结果


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