说明:
(1). 本手册只挑选了有用的信息进行翻译,如要查看完完整整的内容,请自行 info sort。
(2). 译文中,在括号中使用了 "注" 的,为本人所加,非原文内容,助于理解和说明。
(3). 本文的 sort 命令为 CentOS 7.2 上的,版本为 sort (GNU coreutils) 8.22,有些选项在 CentOS 6 上可能不支持,如 "--debug"。
(4). 在没搞懂 sort 处理字段和排序机制时,强烈建议不要看 man sort。
7.1 'sort': Sort text files
===========================
sort 命令用于排序、合并或比较给定文件 (可给定多个) 的所有行,如果没有给定输入文件或输入文件为 "-",则读取标准输入。默认情况下,sort 将操作结果打印在标准输出中。
语法:
sort [OPTION]... [FILE]...
sort 有 3 种操作模式:排序 (默认)、合并以及检查是否已经排过序。使用以下 3 个选项改变操作模式:
'-c'
'--check'
'--check=diagnose-first'
检查给定文件是否已经排序过:如果检测出未排序,将输出诊断信息并以状态码 1 退出,该诊断信息中包含第一个乱序的行。否则以成功状态退出。最多只能给定一个检测文件。
'-C'
'--check=quiet'
'--check=silent'
它类似于 "-c",但不会输出诊断信息。如果文件已排序,则以成功状态退出,否则以状态码 1 退出。最多只能给定一个文件。
'-m'
'--merge'
合并多个文件,每个输入文件必须已经排序。合并时将根据已排序的结果合并为各个组。sort 一般都用来排序,但仍然提供合并功能,因为它的合并速度很快。
sort 排序规则为:按照命令行中给定的字段顺序对给定的字段进行排序,排序时根据为每个字段分配的排序选项进行排序,直到发现不同的排序选项或者排序列结束。如果没有给定排序 key(注:key 即为 - k 指定的值),则对整行进行排序。最后,如果所有给定的 key 的比较结果都相等时,将对整行进行完全默认的排序 (注:即以字母升序排序),但 "-r" 可以改变这次的升、降序结果。这次排序称为 "最后的排序"。使用 "-s" 选项可以禁止 "最后的排序",使得那些排序结果相同的行保留最初的相对顺序。"-u" 选项同样也会禁止 "最后的排序"。
除非明确指定,否则所有的比较都按照 "LC_COLLATE" 指定的字符集的排序规则进行排序。
退出状态码:
0 没有任何错误发生时
1 如果 "-c" 或 "-C" 检测发现输入数据未排序时
2 发生了错误时
如果设置了环境变量 "TMPDIR",sort 将使用它作为临时目录而不是默认的 "/tmp"。"-T" 选项将覆盖该环境变量设置的值。
以下选项影响排序的输出结果。它们既可以指定为全局选项,也可以作为 key 的一部分。如果未指定任何 key,则全局选项将作用于整行,否则指定的 key 将继承全局选项,除非 key 自身也指定了选项 (注:自身指定了选项的 key 将覆盖全局选项)。
为了考虑可移植性,建议将全局选项指定在 "-k"(或"--key") 的前面。
'-b'
'--ignore-leading-blanks'
忽略 key 的前导空白符号 (包括空格、制表符)。不给定该选项时,空白符号对 "-k" 选项指定字符位置有影响 (注:例如"-k 2.2"指定的第 2 个字符可能是空白)。
'-f'
'--ignore-case'
将小写字符当作大写字符。例如,"b" 和 "B" 是相等的。当和 "-u" 选项一起使用时 (注:重复的行只能输出一次),那些小写字符的等价行会被丢弃 (注:也就是说,输出的是大写字符行)。(目前没有任何方法可以抛弃大写字符的等价行,即使使用"-r"也不行,因为在任何时,"-r"选项都只是反转最终的排序结果,不会影响排序过程)。
'-h'
'--human-numeric-sort'
'--sort=human-numeric'
对文件大小格式进行排序。首先对正负性排序 (正数> 0 > 负数),再对大小后缀排序 (0
'-M'
'--month-sort'
'--sort=month'
按字符格式的月份进行排序。
An initial string, consisting of any amount of blanks, followed by a month name abbreviation, is folded to UPPER case and compared in the order 'JAN' <'FEB' <... <'DEC'. Invalid names compare low to valid names.
'-n'
'--numeric-sort'
'--sort=numeric'
按数值排序。空字符串 ""或"\0" 被当作无。数值排序是精确排序,不会四舍五入后排序。
(注:数值排序和默认的排序规则所不同的是,当 key 中遇到非数学字符时,如空白、字母、特殊字符等,将直接结束排序 (在 sort 内部认为找不到匹配值)。也就是说,"-k 2" 和 "-k 2n" 不同,虽然这两个 key 都会扩展到行尾,前者会从第二个字段一直按字符集顺序比较到行尾,而后者可能只对第 2 字段匹配,因为第二字段和第三字段中间可能有特殊符号,导致数值排序直接结束。
因此,对于 "abc 100 200" 这样的输入,指定 "-k 2n" 时,该 key 为 "100 200",但由于中间包含了空白,使得该 key 的排序在第二字段就结束。如果是 "abc 100\0200 200","-k 2n" 在排序时,虽然看上去是 100200,但却只对 100 进行排序,也就是说,如果此时另有一行第 2 字段值为 110,看上去很大的 100200 将小于 110。测试语句:
- echo - e "b 100:200 200\na 110 300" | tr ':''\0' | sort - t ' ' - k2n - k1
因此,对于 "-n" 来说,它绝对不可能跨越 key 的边界。但默认的排序规则会跨越 key 起作用。)
'-r'
'--reverse'
反转比较的结果,使得结果中更大的 key 更早出现。(注:"-r"不会改变排序行为,而是将排序结束后的输出结果进行反转处理,因此只影响排序结束后的输出结果)
'-k POS1[,POS2]'
'--key=POS1[,POS2]'
指定排序的 key,即每行排序的起始和终止字段 (若省略 POS2,则终止位置为行尾)。
POS 的格式为 "F[.C][OPTS]",其中 F 表示字段的序号,C 表示该字段中字符的序号。字段和字符的位置都从 1 开始计算。如果 POS2 的字符位置指定为 0,则表示 POS2 字段中的最后一个字符。如果 POS1 中省略 ".C",则默认值为 1(字段的起始字符),如果 POS2 中省略 ".C",默认值为 0(字段的终止字符)。OPTS 为排序选项,这些选项将覆盖全局选项,使得该 key 可以按照独立的排序选项进行排序。keys 可以跨多个字段。
(注:OPTS 指定在 POS1 和 POS2 的作用是一样的,因为一个"-k"指定一个 key,无论是 POS1 还是 POS2 中的 OPTS 都是对这个 key 有效,但"b"选项除外,见下文)
示例:为了排序第二个字段,使用 "--key=2,2"(-k 2,2)。可使用 "--debug" 选项帮助查看、分析和决定每行中被用于排序的字段。
'--debug'
显示每行中用于排序的部分。还会给出额外的信息。
'-o OUTPUT-FILE'
'--output=OUTPUT-FILE'
将排序的输出结果写入到 OUTPUT-FILE 中。一般来说,sort 在打开 OUTPUT-FILE 前读取完所有输入,因此可以安全地将排序结果保存到输入文件中,就像 "sort -o file1 file1" 和 "cat file1 | sort -o file1" 一样。但是,"-m" 选项会在读取输入前先打开输出文件,因此下面的语句是不安全的语句:
- "cat file1 | sort -m -o file1 -"
'-s'
'--stable'
禁止 sort 执行 "最后的排序"。在没有指定字段选项或全局选项时,该选项将不起作用,除非指定的是 "-r" 选项。
(注:最后的排序:在 key 的比较结果相同时,sort 的最后手段是对整行再进行一次完全默认的排序,即按照字母、升序对整行做最后排序。这称为" 最后的排序 "。如果未指定任何选项,其本身就是完全默认的,因此没必要再做最后的排序。如果指定的是"-r"选项,由于"-r"是对最终结果进行反转排序,因此会影响这次的" 最后的排序 "的结果)
'-t SEPARATOR'
'--field-separator=SEPARATOR'
当在每行中搜索 key 的时候,使用 SEPARATOR 字符作为字段的分隔符。默认情况下,字段是由空白字符和非空白字符之间的空字符串分割而来的。
因此,如果输入行为 "foo bar",默认将切分为两个字段 "foo" 和 "bar",(注:空白和非空白字符之间的空字符为行开头和"oo"后的位置)。字段分隔符不是分隔后字段中的内容,因此 "sort -t' '"对" foo bar"分隔时,将分割为 3 个字段:空字段、"foo"和"bar"。但是,每个单独的字段都是扩展到行结尾的,就像"-k 2",或像"-k 2,3" 包含了范围的字段,它们都在扩展的时候保留字段分隔符。
(注:以 sort -t' '为例,"-k 2"实际上表示的是"foo bar",它扩展到行尾,且中间的字段分隔符被保留。而"-k 1,2"实际上表示的是" foo",因为明确指定了这个 key 到第二个字段结束,但中间的字段分隔符仍保留)
如果要指定字段分隔符为空,则使用 "\0",例如 "sort -t'\0'"。
'--parallel=N'
设置 sort 运行的并行线程数为 N。默认 N 设置为可获得的 cpu 个数,但最大限制为 8,因为超过 8 之后带来的性能收益递减。
'-u'
'--unique'
一般情况下,"-u" 将仅输出排序后重复行的第一行。该选项会禁止 "最后的排序"(注:见前文译文)。
"sort -u" 和 "sort | uniq" 是等价的,但扩展了更多选项后将可能不等价,例如,"sort -n -u" 只会检查数值部分的唯一性,但 "sort -n | uniq" 在 sort 对行的数值排序后,uniq 将检查整个行的唯一性。
'-z'
'--zero-terminated'
使用 "\0" 分割每行而不是使用换行符。
"-k" 指定的 key 后面可以指定 "bfhgnr" 等选项,这种情况下,该 key 将不会继承全局选项。除了 "b" 选项,所有的选项都作用于整个 key,无论该选项是写在 POS1 还是 POS2 上。如果指定了 "b" 选项,它仅独立作用于 POS1 或 POS2 上,但如果继承了全局的 "-b",则会作用于整个 key 上。如果输入行中包含了前导空白字符,且没有使用 "-t" 选项,"-k" 通常会结合 "-b" 或某些隐含了忽略前导空白字符的选项 (ghn) 一起使用,否则前导空白字符可能会导致划分的字段非常混乱。
如果 POS 中指定的字段或字符位置超出了行尾或字段,则该 key 为空。如果指定了 "-b" 选项,".C" 部分将从字段的第一个非空白字符开始计算。
以下是一些示例,用于说明不同选项的结合使用:
- sort - n - r
- sort - k 3b
- sort -t : -k 2,2n -k 5.3,5.4
(注:任何时候,只想对某字段进行排序时,都建议明确指定其起始和结束位置)
注意,如果写的是 "-k 2n" 而不是 "-k 2,2n",该 key 将从第二字段一直扩展到行尾,这是主排序 key,而副排序 key"-k 5.3,5.4" 在主排序 key 的排序基础上再按照字母排序。绝大多数情况下,让 key 向后扩展一般不是所期望的行为。
还需注意,"n" 选项作用范围为第一个 key。这等价于 "-k 2n,2" 或 "-k 2n,2n"。所有的修饰符,除了 "-b",无论写在 pos1 还是 pos2,都会作用于整个 key。
(注:由于 n 选项无法跨越 key,因此上面即使写成了"-k 2n" 也是等价的,但下面两个命令则不一样:
- sort -t : -k 2 -k 5.3,5.4n
- sort -t : -k 2,2 -k 5.3,5.4n
由于默认的字符集排序规则会跨越 key,第一条命令中主 key 从第 2 字段开始,直到行尾结束,于是会先对整个 key 按字符排序,然后在此基础上再对副 key 按数值排序。
再如下面的例子:即使主 key 的字段在副 key 的字段后面,副 key 由于是做字符集排序,所以仍会跨越主 key。)
- sort - t: -k 5n - k 2
- 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
以上三个命令是等价的。第一个命令指定了第一个 key 的 POS1 要忽略前导空白,且第二个 key 要按照数值排序。另外两个命令中,缺少选项的 key 将继承全局选项。此处继承之所以能正确工作,是因为 "-k 5b,5b" 和 "-k 5b,5" 是等价的。
4.150.156.3 - - [01/Apr/2004:06:31:51 +0000] message 1
211.24.3.231 - - [24/Apr/2004: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
该示例无法仅使用一个 sort 语句实现,因为 IPV4 地址需要使用 "." 分隔,而时间戳需要使用空格分隔。因此,使用两个 sort 语句:第一个 sort 语句按照时间戳排序,第二个语句按照 IPV4 排序。第一个 sort 命令中使用 "-k" 将每个字段进行隔离,先按照年排序,再按照月份排序,接着是日,最后对 "时: 分: 秒" 排序。除了 "时: 分: 秒" 这个 key,其余的 key 都没必要指定 key 的结束位置,因为 "n" 和 "M" 选项作用范围不能跨域每个 key 的左边界。第二个 sort 命令是对 ipv4 地址按照字典顺序排序的。第二个 sort 语句中使用了 "-s" 选项,以防止主排序 key 的关系被副排序 key 破坏,第一个 sort 语句中使用 "-s" 选项是为了保证两个 sort 语句在 "-s" 属性上的一致性。
(注:由于 n 选项无法跨越 key 边界和非数学字符,因此上面第二个 sort 命令和下面的命令是等价的:)
- sort - s - t '.' - n - k1 - k2 - k3 - k4
回到系列文章大纲:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
来源: http://www.cnblogs.com/f-ck-need-u/p/7439878.html