就地和递归地排序和删除重复项

Jam*_*mes 4 debian recursive sort uniq text

我想对所有子目录中的所有文件进行排序。我在 256 个目录中有 65536 个文件,每个文件一行一个字,每个文件都包含重复项。

我想要的是使用 -u 选项对它们进行排序(我不知道为什么,但是如果我将 sort 传递给 uniq -u 命令,它实际上会删除重复的唯一行,这很奇怪,但无论如何),但我不这样做想要任何输出文件,我想排序读取内存中的文件,然后覆盖它们。我尝试了 -o 选项,但它需要一个文件名。

有没有办法递归地执行这个?

谢谢 :)

Sté*_*las 6

那可能只是:

find . -type f -size +1c -exec sort -uo {} {} ';'
Run Code Online (Sandbox Code Playgroud)

(此处跳过小于 2 字节大的文件,因为您需要至少 3 个字节来创建两个不同的行,或者可能需要 2 个字节,"\nx"其中一个空行后跟一个未定界的行¹)。

注意默认的排序顺序sort是基于语言环境的整理算法。

两行可以排序相同,即使它们不是逐字节相同的,尤其是当这些行包含不构成有效字符的字节序列时,以及在 Debian 等 GNU 系统上排序顺序不相同的字符时定义。

你可以做:

LC_ALL=C find . -type f -exec sort -uo {} {} ';'
Run Code Online (Sandbox Code Playgroud)

相反,在基于 ASCII 的系统(例如所有架构和内核上的 Debian)上,它将按字节值而不是语言环境整理顺序(或 IOW,C 语言环境的整理顺序基于字节值)对行进行排序,并且应该保证两个字节到字节不同的行排序不一样。

这对sort每个文件运行一次调用。如果文件相当短,要加快速度,您可以改为zsh

zmodload zsh/mapfile
for f (**/*(N.)) print -rC1 -v 'mapfile[$f]' - ${(fou)mapfile[$file]}
Run Code Online (Sandbox Code Playgroud)

这避免了sort多次运行外部命令,而是使用其ou参数扩展标志来对行进行排序和唯一化。请注意,它会删除输入中的空行(如果有),并跳过隐藏文件(如果需要,请添加Dglob 限定符)。

与 GNU 相反sort -uzsh不会将两个字节到字节不同的字符串视为重复(即使它们的排序相同),因此您无需将语言环境固定为 C 那里。

$ 语言环境标题charmap
英国的英语语言环境
UTF-8
$ a=( )
$ 打印 -rC1 - $a | 排序 -u
  (哎呀,吸血鬼消失了,因为它和仙女一样排序)
$ 打印 -rC1 - ${(ou)a}


至于您关于 的问题uniq -u,这就是它的用途,uniq -u报告输入中唯一的行。要删除重复项,只需sort | uniq. 的补充uniq -u将是uniq -D(报告所有重复的行)。

GNUuniq过去常常报告排序相同的行序列中的第一个(因此sort -u将与 相同sort | uniq)。较新的版本报告相同行的第一个序列,因此sort | uniq如果可以有不同的行排序相同,则不能再使用。

在这里,使用较新的 GNU 版本:

$ print -rC1      | sort | uniq




Run Code Online (Sandbox Code Playgroud)

由于精灵和吸血鬼在我的语言环境中排序相同,因此sort结果将与输入中的一样(因为 GNUsort使用稳定的排序算法),并且uniq仅当输入发生在原始包含相邻重复项时才会删除重复项。

我们可以做的是首先sort按字节值,然后在调用之前按整理顺序uniq

LC_ALL=C sort | sort | LC_ALL=C uniq
Run Code Online (Sandbox Code Playgroud)

调用uniqunderLC_ALL=C将使旧版本和新版本的工作方式相同。


sort如果输入中缺少该换行符,则会添加回该换行符,实际上是从该非文本文件中生成文本文件。通过跳过包含非换行字节的 1 字节大小的文件,这意味着这些文件不是固定的,因此如果您仍然想要该文本文件修复的好处,您可能希望跳过该优化,或者将优化扩展到-size +2cif你知道你所有的文件都是格式正确的文本文件。