Sort:对文本文件进行排序

来自泡泡学习笔记
跳到导航 跳到搜索

sort命令用于对文本文件进行排序、合并或比较。如果没有指定文件,或者指定的文件为“-”,则从标准输入中读取数据。默认情况下,sort将结果写入标准输出。


语法:

sort [选项]... [文件]...


许多选项会影响sort如何比较行;如果结果出乎意料,请尝试使用–debug选项查看发生了什么。一对行按照以下方式进行比较:sort根据关联的排序选项按照命令行上指定的顺序比较每对字段(参见–key),直到找到差异或没有剩余字段为止。如果没有指定键字段,sort将使用整行的默认键。最后,当所有键都相等时,作为最后的手段,sort会像没有指定–reverse(-r)以外的排序选项一样比较整个行。–stable(-s)选项禁用了这种最后的手段比较,以便在所有这些字段都相等的行中保留其原始相对顺序。–unique(-u)选项也禁用了最后的手段比较。

除非另有说明,否则所有比较都使用由LC_COLLATE locale指定的字符排序序列。一行的尾随换行符在比较目的中不被视为该行的一部分。如果输入文件的最后一个字节不是换行符,GNU sort会静默地提供一个。GNU sort(如对所有GNU实用程序的规定)对输入行的长度没有限制,也不限制允许在行内的字节数。


操作模式

sort有三种操作模式:sort(默认)、merge和检查顺序。以下选项可以改变操作模式:


-c

–check

–check=diagnose-first

检查给定的文件是否已经排序:如果它不是全部排序,打印一个包含第一个乱序行的诊断信息并退出,状态为1。否则,成功退出。最多只能给出一个输入文件。


-C

–check=quiet

–check=silent

如果给定的文件已经排序,则成功退出,否则以状态1退出。最多只能给出一个输入文件。这与-c类似,只是它不会打印诊断信息。


-m

–merge

将给定的文件按组排序。每个输入文件必须始终单独排序。总是可以排序而不是合并;合并是提供因为它更快,在可以工作的情况下。


退出状态:

  • 0 如果没有发生错误
  • 1 如果使用-c或-C并且输入未排序
  • 2 如果发生错误

如果设置了环境变量TMPDIR,sort将使用其值作为临时文件的目录,而不是/tmp。–temporary-directory(-T)选项反过来会覆盖环境变量。


选项

以下选项影响输出行的顺序。它们可以全局指定或作为特定键字段的一部分指定。如果没有指定键字段,全局选项将应用于整个行的比较;否则,没有特殊选项的键字段将继承全局选项。在pre-POSIX版本的sort中,全局选项仅影响后续键字段,因此可移植的shell脚本应该首先指定全局选项。


-b

–ignore-leading-blanks

在查找每行排序键时忽略前导空格。默认情况下,空格或制表符是空格,但LC_CTYPE区域设置可以更改此设置。请注意,您的区域设置的排序规则可能会忽略空格,但没有这个选项,空格将在用-k选项指定的键中指定字符位置时具有重要意义。


-d

–dictionary-order

按字典顺序排序:在排序时忽略所有字符,除了字母、数字和空格。默认情况下,字母和数字是ASCII字符,空格是空格或制表符,但LC_CTYPE区域设置可以更改此设置。


-f

–ignore-case

在比较时折叠小写字符为等效的大写字符,例如,“b”和“B”将视为相等。LC_CTYPE区域设置确定字符类型。与–unique一起使用时,这些小写等效行将被丢弃。(目前没有方法来丢弃大写等效行。(任何–reverse给出的只会影响最终结果,在丢弃之后。))


-g

–general-numeric-sort

–sort=general-numeric

按数字排序,将每行的前缀转换为长双精度浮点数。参见浮点数。不要报告溢出、下溢或转换错误。使用以下排序序列:

  • 不以数字开头的所有行都被认为是相等的。
  • NaN(IEEE浮点算术中的“非数字”值)在一致但机器依赖的顺序中。
    • 负无穷大。
    • 按升序排列的有限数字(带有-0和+0等于)。
    • 正无穷大。


只有在没有其他选择的情况下才能使用此选项;它比–numeric-sort(-n)慢得多,并且在转换为浮点数时可能会丢失信息。

您可以使用此选项对以“0x”或“0X”为前缀的十六进制数字进行排序,其中这些数字不是固定宽度的,或者大小写不一致。但是,对于一致的大小写且左填充为“0”的一致性宽度的十六进制数字,标准的字典排序将更快。


-h

–human-numeric-sort

–sort=human-numeric

按数字排序,首先按数字符号(负数、零或正数);然后按SI后缀(空的、‘k’或’K’,或’MGTPEZYRQ’中的一个,按此顺序;参见块大小);最后按数值。例如,“1023M”在“1G”之前排序,因为“M”(兆)在“G”(吉)作为SI后缀之前。此选项按最接近的后缀缩放值进行排序,无论后缀是否表示1000的幂或1024,因此它可以对任何单个调用df、du或ls命令的结果进行排序,这些命令使用它们的–human-readable或–si选项调用。数字的语法与–numeric-sort选项相同;SI后缀必须紧跟在数字之后。还请注意numfmt命令,可以在排序后重新格式化数字以进行人类操作,因此通常允许sort对更准确的数字进行操作。


-i

–ignore-nonprinting

忽略非打印字符。LC_CTYPE区域设置确定字符类型。如果给出了更强大的–dictionary-order(-d)选项,则此选项无效。


-M

–month-sort

–sort=month

将一个由任意数量的空格组成的初始字符串,后面跟着一个月份缩写,折叠为大写并按顺序比较’JAN’ < ‘FEB’ < … < ‘DEC’。无效的名称与有效名称进行比较。LC_TIME区域设置确定月份拼写。默认情况下,空格或制表符被视为空白,但LC_CTYPE区域设置可以更改此设置。


-n

–numeric-sort

–sort=numeric

按数字排序。每行以可选的空格、可选的“-”符号和零个或多个可能由千位分隔符分隔的数字开始,可选地后跟一个小数点字符和零个或多个数字。空数字被视为“0”。LC_NUMERIC区域设置指定小数点字符和千位分隔符。默认情况下,空格或制表符被视为空白,但LC_CTYPE区域设置可以更改此设置。


比较是精确的;没有舍入误差。

既没有前导“+”符号,也没有指数表示法。要对这些字符串进行数值排序,请使用–general-numeric-sort(-g)选项。


-V

–version-sort

按版本名称和数字排序。它的行为类似于标准排序,但每个十进制数字序列都将其视为索引/版本号。(参见版本排序顺序。)


-r

–reverse

反转比较结果,使具有较大键值的行在输出中出现在较晚的位置,而不是较早的位置。


-R

–random-sort

–sort=random

通过对输入键进行哈希并排序哈希值来对其进行排序。选择随机哈希函数,确保其无碰撞,以便不同的键具有不同的哈希值。这与输入的随机排列类似(参见shuf:Shuffling text),但具有相同值的键会一起排序。


如果指定了多个随机排序字段,则对所有字段使用相同的随机哈希函数。要为不同字段使用不同的随机哈希函数,您可以多次调用sort。

选择哈希函数的方式受–random-source选项的影响。


–compress-program=prog

使用程序prog压缩任何临时文件。

如果没有参数,prog必须将标准输入压缩到标准输出,并在给定-d选项时将标准输入解压缩到标准输出。


如果prog以非零状态退出,则终止。

空格和反斜杠字符不应出现在prog中;它们保留用于将来使用。


–files0-from=file

禁止处理命令行上命名的文件,而是处理file文件中命名的文件;每个名称以零字节(ASCII NUL)结尾。当文件名列表太长以至于可能超过命令行长度限制时,这是有用的。在这种情况下,通过xargs运行sort是不理想的,因为它将列表分成块,并为每个子列表打印排序输出,而不是整个列表的排序输出。一种生成ASCII NUL结尾的文件名列表的方法是使用GNU find,使用其-print0谓词。如果file是“-”,则从标准输入读取ASCII NUL结尾的文件名。


-k pos1[,pos2]

–key=pos1[,pos2]

指定一个由pos1和pos2(或省略pos2)之间的行部分(或行末,如果省略pos2)组成的排序字段。


最简单的形式是pos指定字段编号(从1开始),字段由连续的空白字符分隔,默认情况下,这些空白字符在每个字段的开头处包含在内。要调整空白字符的处理方式,请参阅-b和-t选项。


更一般地说,每个pos的形式为“f[.c][opts]”,其中f是要使用的字段编号,c是从字段开头的字符编号。字段和字符位置从1编号;pos2中的字符位置为零表示字段的最后一个字符。如果省略pos1中的“.c”,则默认为1(字段的开头);如果省略pos2中的“.c”,则默认为0(字段的末尾)。opts是排序选项,允许根据不同规则对单个键进行排序。键可以跨越多个字段。


示例:要按第二字段排序,请使用–key=2,2(-k 2,2)。


–debug

突出显示用于排序的每一行的部分。还将向标准错误发出关于可疑用法的警告。


–batch-size=nmerge

一次最多合并nmerge个输入。


当sort需要合并超过nmerge个输入时,它将它们分组为nmerge组,将结果保存在临时文件中,然后将该临时文件用作后续合并的输入。


nmerge的值越大,合并性能可能会提高,同时减少临时存储的使用,但这会增加内存使用和I/O。相反,nmerge的值越小,可以减少内存需求和I/O,同时减少临时存储消耗和合并性能。 nmerge的值必须至少为2。当前值为16,但这是实现依赖的,可能会在未来发生变化。


nmerge的值可能受到打开文件描述符的资源限制。可以使用命令‘ulimit -n’或‘getconf OPEN_MAX’查看您的系统的资源限制;如果程序已经打开了一些文件,或者操作系统对打开文件的数量有其他限制,这些限制可能会进一步修改。如果nmerge的值超过了资源限制,sort将静默地使用较小的值。


-o output-file

–output=output-file

将输出写入output-file而不是标准输出。通常,sort在打开output-file之前读取所有输入,因此您可以使用命令如sort -o F F和cat F | sort -o F来对文件进行原地排序。然而,通常更安全的做法是将输出写入一个未使用的文件中,因为如果在系统崩溃或sort遇到I/O或其他严重错误时对文件进行原地排序,数据可能会丢失。此外,使用–merge(-m)选项的sort可以在读取所有输入之前打开输出文件,因此命令如cat F | sort -m -o F - G是不安全的,因为sort可能在cat完成读取它之前就开始写入F。


在较新的系统中,如果设置了POSIXLY_CORRECT,则在输入文件之后不能出现-o选项,例如,‘sort F -o F’。可移植脚本应在任何输入文件之前指定-o output-file。


–random-source=file

使用file作为用于确定使用哪个随机哈希函数的随机数据的源,该随机哈希函数与-R选项一起使用。


-s

–stable

通过禁用其最后的手段比较来使sort稳定。如果没有指定除–reverse(-r)之外的任何字段或全局排序选项,则此选项无效。


-S size

–buffer-size=size

使用给定大小的主内存排序缓冲区。默认情况下,大小以1024字节为单位。附加’%‘将大小解释为物理内存的百分比。附加’K’将大小乘以1024(默认值),附加’M’将大小乘以1,048,576,附加’G’将大小乘以1,073,741,824,依此类推,附加’T’、‘P’、‘E’、‘Z’、‘Y’、‘R’和’Q’。附加’b’将大小解释为字节计数,不进行乘法。


此选项可以通过使sort以比默认更大的或更小的排序缓冲区开始来提高性能。然而,此选项仅影响初始缓冲区大小。


-t separator

–field-separator=separator

在查找每行中的排序键时,使用字符分隔符作为字段分隔符。默认情况下,字段由非空白字符和空白字符之间的空字符串分隔。默认情况下,空白是一个空格或制表符,但LC_CTYPE区域设置可以更改此设置。


换句话说,给定输入行’ foo bar’,sort将其分解为字段’ foo’和’ bar’。字段分隔符不被认为是字段前或字段后的组成部分,因此使用’sort -t ” “‘,相同的输入行具有三个字段:一个空字段,’foo’,和’bar’。然而,从-k 2开始的字段,或者由-k 2,3组成的字段,保留端点之间的字段分隔符。


要指定ASCII NUL作为字段分隔符,请使用两个字符的字符串’\0’,例如,‘sort -t’\0’’。


-T tempdir

–temporary-directory=tempdir

使用tempdir目录存储临时文件,覆盖TMPDIR环境变量。如果此选项给出多次,临时文件将存储在所有给定的目录中。如果您有一个大型排序或合并,它是I/O绑定的,您通常可以通过使用此选项指定不同文件系统的目录来提高性能。


–parallel=n

设置并行运行的排序数量为n。默认情况下,n设置为可用处理器的数量,但限制为8,因为在此之后的性能收益会减少。请注意,使用n个线程会增加内存使用量,其因子为log n。


-u

–unique

通常,只输出与连续相等的序列的第一行。对于–check(-c或-C)选项,检查没有连续的两行比较相等。

此选项还禁用了默认的最后补救措施。


命令sort -u和sort | uniq是等价的,但这种等价性并不扩展到任意排序选项。例如,sort -n -u仅在检查唯一性时检查初始数字字符串的值,而sort -n | uniq检查整行。


-z

–zero-terminated

用零字节而不是换行符(ASCII LF)分隔项目。即,将输入视为由ASCII NUL和零字节分隔的项目,并以ASCII NUL终止输出项目。此选项可以与’perl -0’或’find -print0’以及’xargs -0’一起使用,以便可靠地处理任意文件名(即使其中包含空格或其他特殊字符)。


说明

历史(BSD和System V)实现的sort对某些选项的解释有所不同,特别是-b、-f和-n。GNU sort遵循POSIX行为,通常(但不是总是!)类似于System V行为。根据POSIX,-n不再意味着-b。为了保持一致性,-M已以相同的方式更改。这可能会影响在某些情况下字段规范中字符位置的含义。唯一的修复方法是添加显式的-b。


使用-k指定排序字段的位置可能具有字母’MbdfghinRrV’的任何选项字母,在这种情况下,该特定字段不会继承全局排序选项。-b选项可以独立地附加到字段规范的开始和结束位置,如果它从全局选项继承,它将附加到两者。如果输入行可以包含前导或相邻的空白,并且未使用-t,那么通常将-k与-b或隐式忽略前导空白的选项(如‘Mghn’)组合,否则由于字段中的前导空白数量的不同可能会导致令人困惑的结果。

如果排序字段规范的开始位置落在行的末尾或在结束字段之后,则该字段为空。如果指定了-b选项,则字段规范的“.c”部分从字段的第一个非空白字符计算。


不符合POSIX 1003.1-2001标准的系统支持传统原点零语法“+pos1 [-pos2]”以指定排序键。传统命令“sort +a.x -b.y”相当于“sort -k a+1.x+1,b”,如果y是“0”或不存在,则等于“sort -k a+1.x+1,b+1.y”。


这种传统行为可以通过_POSIX2_VERSION环境变量(参见标准符合性)控制;也可以通过在未设置POSIXLY_CORRECT时使用带有“-pos2”的传统的语法来启用。

应在标准主机上避免传统语法,并应使用-k代替。例如,避免使用“sort +2”,因为这可能被解释为“sort ./+2”或“sort -k 3”。如果您的脚本还必须在仅支持传统语法的主机上运行,可以使用测试“if sort -k 1 </dev/null >/dev/null 2>&1; then …”来决定使用哪种语法。


示例

以下是一些示例,说明了各种选项组合。

按降序(反向)数字顺序排序。

sort -n -r


最多同时运行4个排序,缓冲区大小为10M。

sort --parallel=4 -S 10M


按字母顺序排序,忽略第一个和第二个字段以及第三个字段开头的空格。这使用一个由第三个字段开始的第一个非空白字符到每行的末尾组成的单个键。

sort -k 3b


按第二个字段的数字顺序排序,通过在第五个字段的第三和第四个字符上按字母顺序解决平局。使用“:”作为字段分隔符。

sort -t : -k 2,2n -k 5.3,5.4


注意:如果你写了-k 2n而不是-k 2,2n,那么sort将使用从第二个字段开始到行尾的所有字符作为主要数字键。对于大多数应用程序,将跨越多个字段的键视为数字不会像你期望的那样工作。


此外,’n’修饰符应用于第一个键的字段结束指定器。它等同于指定-k 2n,2或-k 2n,2n。除’b’之外的所有修饰符都适用于关联字段,无论修饰符字符是否附加到键指定器的字段开始和/或字段结束部分。


按第五个字段对密码文件进行排序,并忽略任何前导空格。按第三字段的数字用户ID对具有相等值的第五个字段的行进行排序。字段由“:”分隔。

sort -t : -k 5b,5 -k 3,3n /etc/passwd
sort -t : -n -k 5b,5 -k 3,3 /etc/passwd
sort -t : -b -k 5,5 -k 3,3n /etc/passwd


这三个命令具有等效效果。第一个指定第一个键的起始位置忽略前导空格,第二个键按数字顺序排序。其他两个命令依赖于缺少修饰符的全局选项被继承给sort键。在这种情况下,由于-k 5b,5b和-k 5b,5是等效的,因为缺少’.c’字符位置的位置不受初始空格跳过的影响。


按一组日志文件进行排序,主要按IPv4地址和次要按时间戳排序。如果两行的主要和次要键相同,则按输入顺序输出行。

日志文件包含如下所示的行:

4.150.156.3 - - [01/Apr/2020:06:31:51 +0000] message 1
211.24.3.231 - - [24/Apr/2020:20:17:39 +0000] message 2


字段由恰好一个空格分隔。按IPv4地址字典顺序排序,例如,212.61.52.2在212.129.233.201之前,因为61小于129。

sort -s -t ' ' -k 4.9n -k 4.5M -k 4.2n -k 4.14,4.21 file*.log |
sort -s -t '.' -k 1,1n -k 2,2n -k 3,3n -k 4,4n


这个例子不能在一个POSIX sort调用中完成,因为IPv4地址组件由’.’分隔,而日期紧跟在一个空格之后。所以它被分解成两个sort调用:第一个按时间戳排序,第二个按IPv4地址排序。时间戳按年份、月份、日期和最后小时-分钟-秒字段排序,使用-k来隔离每个字段。除了小时-分钟-秒之外,不需要指定每个键字段的结束,因为’n’和’M’修饰符根据前缀的前缀边界进行排序。IPv4地址按字典顺序排序。第二个排序使用’-s’,以便主要键的平局由次要键打破;第一个排序使用’-s’,以便两个排序的组合是稳定的。请注意,作为GNU扩展,上面的示例可以通过使用类似’-k1,1V’的sort命令对IPv4地址字段进行排序来实现单个sort调用。


生成不区分大小写的标签文件。

find src -type f -print0 | sort -z -f | xargs -0 etags --append


在这种情况下,使用-print0、-z和-0意味着文件名包含空格或其他特殊字符的文件不会被sort操作拆分。


使用常见的DSU,装饰排序解除装饰idiom按长度对行进行排序。

awk '{print length, $0}' /etc/passwd | sort -n | cut -f2- -d' '


一般来说,这种方法可以用于直接对sort命令不支持或效率低下的数据进行排序。


打乱目录列表,但保留每个目录内的文件顺序。

例如,可以使用此方法生成音乐播放列表,其中专辑被打乱,但每个专辑的歌曲按顺序播放。


ls */* | sort -t / -k 1,1R -k 2,2