我在任何地方看到有人需要获得一个排序的、唯一的列表,他们总是通过管道传输到sort | uniq. 我从未见过有人使用的例子sort -u。为什么不?有什么区别,为什么使用 uniq 比使用 unique 标志进行排序更好?
Chr*_*own 150
sort | uniq之前存在sort -u,并且与更广泛的系统兼容,尽管几乎所有现代系统都支持-u- 它是 POSIX。它主要是回到sort -u不存在的时代(如果他们知道的方式继续有效,人们不会倾向于改变他们的方法,看看ifconfig与ip采用)。
这两者很可能合并,因为删除文件中的重复项需要排序(至少在标准情况下),并且是排序的一个非常常见的用例。由于能够同时执行两个操作(并且由于它在uniq和之间不需要 IPC 的事实),它在内部也更快sort。特别是如果文件很大,sort -u很可能会使用较少的中间文件来对数据进行排序。
在我的系统上,我一直得到这样的结果:
$ dd if=/dev/urandom of=/dev/shm/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.95208 s, 11.7 MB/s
$ time sort -u /dev/shm/file >/dev/null
real 0m0.500s
user 0m0.767s
sys 0m0.167s
$ time sort /dev/shm/file | uniq >/dev/null
real 0m0.772s
user 0m1.137s
sys 0m0.273s
Run Code Online (Sandbox Code Playgroud)
它也不会掩盖 的返回码sort,这可能很重要(在现代 shell 中,有一些方法可以获得它,例如,bash的$PIPESTATUS数组,但这并不总是正确的)。
Sté*_*las 53
使用 POSIX 兼容sorts 和uniqs(GNUuniq目前在这方面不兼容),不同之处在于sort使用语言环境的整理算法来比较字符串(通常用于strcoll()比较字符串),同时uniq检查字节值标识(通常会使用strcmp()) ¹。
这至少有两个原因。
在某些语言环境中,尤其是在 GNU 系统上,有不同的字符排序相同。例如,在 GNU 系统上的 en_US.UTF-8 语言环境中,所有 ??????????... 字符² 和许多其他字符的排序相同,因为它们的排序顺序没有定义。0123456789 阿拉伯数字的排序与其东阿拉伯印度语数字相同(??????????)。
对于sort -u, ? 排序与 ? 和0123一样????所以sort -u会只保留其中的一个,而 for uniq(不是 GNUuniq使用strcoll()(除了 with -i)),?不同于? 和 0123 与 ???? 不同,因此uniq会认为所有 4 个都是唯一的。
strcoll只能比较有效字符的字符串(当输入具有不构成有效字符的字节序列时,行为未根据 POSIX 定义),strcmp()而不关心字符,因为它只进行字节到字节的比较。所以这是另一个原因,sort -u如果其中一些不能形成有效的文本,则可能不会为您提供所有独特的行。sort|uniq,虽然在非文本输入上仍未指定,但实际上由于这个原因更有可能为您提供独特的行。
除了这些微妙之处,到目前为止还没有注意到的一件事是在uniq词法上比较整行,而sort's-u根据命令行上给出的排序规范进行比较。
$ printf '%s\n' 'a b' 'a c' | sort -uk 1,1
a b
$ printf '%s\n' 'a b' 'a c' | sort -k 1,1 | uniq
a b
a c
$ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq
0
-0
+0
00
$ printf '%s\n' 0 -0 +0 00 '' | sort -nu
0
Run Code Online (Sandbox Code Playgroud)
¹ 之前版本的 POSIX 规范引起了混淆,但是通过将LC_COLLATE变量列为影响uniq,这在 2018 版中被删除,并且在上述讨论之后澄清了行为。查看对应的Austin组bug
² 2019年编辑。这些已经被修复,但超过 95% 的 Unicode 代码点在 GNU libc 的 2.30 版中仍然具有未定义的顺序。例如,您可以在较新版本中进行测试
CLF*_*CLF 51
一个区别是它uniq有许多有用的附加选项,例如跳过字段进行比较和计算值的重复次数。sort的-u标志仅实现未修饰uniq命令的功能。
我更喜欢使用,sort | uniq因为当我尝试使用-u(eliminate duplicates) 选项删除涉及混合大小写字符串的重复项时,结果并不容易理解。
注意:在运行下面的示例之前,您需要通过执行以下操作来模拟标准的 C 整理序列:
LC_ALL=C
export LC_ALL
Run Code Online (Sandbox Code Playgroud)
例如,如果我想对文件进行排序并删除重复项,同时保持字符串的不同情况不同。
$ cat short #file to sort
Pear
Pear
apple
pear
Apple
$ sort short #normal sort (in normal C collating sequence)
Apple #the lower case words are at the end
Pear
Pear
apple
pear
$ sort -f short #correctly sorts ignoring the C collating order
Apple #but duplicates are still there
apple
Pear
Pear
pear
$ sort -fu short #By adding the -u option to remove duplicates it is
apple #difficult to ascertain the logic that sort uses to remove
Pear #duplicates(i.e., why did it remove pear instead of Pear?)
Run Code Online (Sandbox Code Playgroud)
这种混淆是通过不使用-u删除重复项的选项来解决的。使用uniq更可预测。下面首先排序并忽略大小写,然后将其传递给以uniq删除重复项。
$ sort -f short | uniq
Apple
apple
Pear
pear
Run Code Online (Sandbox Code Playgroud)
小智 6
我今天发现的另一个区别是基于分隔符进行sort -u排序时,仅在您排序的列上应用唯一标志。
$ cat input.csv
3,World,1
1,Hello,1
2,Hello,1
$ cat input.csv | sort -t',' -k2 -u
1,Hello,1
3,World,1
$ cat input.csv | sort -t',' -k2 | uniq
1,Hello,1
2,Hello,1
3,World,1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
217511 次 |
| 最近记录: |