sort

sort

Linux sort 命令用于将文本文件内容加以排序。sort 可针对文本文件的内容,以行为单位来排序

sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件][-k field1[,field2]]

常用选项 -b -f -n -u -r -t -k


-t 和 [-k field1[,field2]] 就适合那种有明确的表格结构的文本的排序,比如 /etc/passwd。比如对这个文件以 : 进行分割的第一列和第二列进行排序,注意,这个时候要用数字排序

cat etc/passwd | sort -n -t ':' -k 1,3:会先对第一列排序,然后对第二列排序。

不是用管道也可以:sort -n -t ':' -k 1,3 /etc/passwd

拓展

-t-k 还可以进行更加精细的控制。

一个 -k 参数的详细语法如下:

[ FStart [ .CStart ] ] [ Modifier ] [ , [ FEnd [ .CEnd ]][ Modifier ] ]

这个语法格式可以被其中的逗号(,)分为两大部分,Start 部分和 End 部分。

先灌输一个思想,那就是:如果不设定 End 部分,那么就认为 End 被设定为行尾。这个概念很重要的,但往往被忽视。

Start 部分也由三部分组成,

  1. 先重点说说 Start 部分的 FStart 和 .CStartFStart.CStart,其中 FStart 就是表示使用的域,经过 -t 参数分割成多个块,每一块就是一个域,而 CStart 则表示在 FStart 域中从第几个字符开始算 " 排序首符 "。.CStart 也是可以省略的,省略的话就表示从本域的开头部分开始。之前例子中的 -k 2-k 3 就是省略了 .CStart 的例子。

  2. 同理,在 End 部分中,你可以设定 FEnd.CEnd,如果你省略 .CEnd,则表示结尾到 " 域尾 ",即本域的最后一个字符。或者,如果你将 CEnd 设定为 0(零),也是表示结尾到 " 域尾 "。

  3. 最后说 Modifier,可以用到 b、d、f、i、n 或 r。

    • n 与 sort 的 -n 参数相同,依照数值的大小排序

    • r 与 sort 的 -r 参数相同,以相反的顺序来排序

    • b 与 sort 的 -b 参数相同,表示忽略本域的开始位置的空白符号。

    • d 表示对本域按照字典顺序排序(即,只考虑空白和字母)。

    • f 表示对本域忽略大小写进行排序。

    • i 表示忽略 " 不可打印字符 ",只针对可打印字符进行排序。(有些 ASCII 就是不可打印字符,比如 \a 是报警,\b 是退格,\n 是换行,\r 是回车等等)

符合我们直觉的排序是,在前一个域相同的情况下对第二个域进行排序,但是 sort 默认不完全是这样的,

比如一个 txt 文件,第一列是文本,第二列是数字,通过 sort -t ':' -k 1,2n file.txt 无法实现先对第一列按照文本正序排列,然后在第一列相同的情况下对第二列按照数字进行正序排列,只能分为两个 -k 参数,sort -t ':' -k 1,1 -k 2,2n file.txt。当然,如果第一列和第二列都是文本或者都是数字 sort -t ':' -k 1n,2n file.txt 就可以正常排序。

多列(域)排序的时候,把多列写在一个 -k 参数中,和多个 -k 参数中也是有区别的。

多个 -k 参数实际上是在设定域排序的优先级-k 1,1 -k 2,2 的意思是先以第 1 个域进行排序,如果相同,再以第 2 个域进行排序,选择使用多个 -k 参数的写法,更符合我们的直觉

例如,

sort -t ':' -k 1,1 -k 2,2r file.txt:先对第一列正序排列(默认),再对第二列倒序排列

sort -t ':' -k 1.2,1 -k 2,2nr file.txt:从第一列的第二个位置(直到域尾)开始排序,按照文本正序排列,第二列按照数字倒序排列,注意,取第一个域的第二位到域尾的写法是 -k 1.2,1

sort -t ':' -k 1.2,1.2 -k 2,2nr file.txt:只对第一列的第二个位置排序,第二列按照数字倒序排列

由于只对第二个字母进行排序,所以我们使用了 -k 1.2,1.2 的表示方式,表示我们 " 只 " 对第二个位置进行排序。如果你问 " 我使用 -k 1.2 怎么不行?",当然不行,因为你省略了 End 部分,这就意味着你将对从第二个位置起到最后一个域位置的内容进行排序。第二列,我们也使用了 -k 2,2,这是最准确的表述,表示我们 " 只 " 对本域进行排序,因为如果你省略了后面的 2,就变成了我们 " 对第 2 个域开始到最后一个域位置的内容进行排序 " 了。

配合 -u-u 会比较所有的参于排序的内容,全部相同,才会去重,比如你只选了一个域,或者只选了一个域中的某几位,那么 -u 就只比较这几位,