sort排序,在处理单个域排序时基本没有什么问题,都能正确显示我们期望的结果,但是在涉及到多个域进行排序是就有很多小细节需要注意了。
先看看示例的文档:

1
2
3
4
5
yu@yu-vm:~/0510$ cat test4
google 110 5000
baidu 100 10000
guge 50 3000
sohu 100 4500

第一列表示公司名称,第二列表示人数,第三列表示工资
现在按照人数进行排序下:

1
2
3
4
5
yu@yu-vm:~/0510$ cat test4|sort -k2
baidu 100 10000
sohu 100 4500
google 110 5000
guge 50 3000

好像不太像我们想象的那样,原因就是此处是按照字符串进行排序的,5比1大,所以50排在后面。

1
2
3
4
5
yu@yu-vm:~/0510$ cat test4|sort -n -k2
guge 50 3000
baidu 100 10000
sohu 100 4500
google 110 5000

指定一个-n,要求以数值进行排序,OK。
这时候我们希望按照人数及待遇排序

1
2
3
4
5
yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3
guge 50 3000
sohu 100 4500
baidu 100 10000
google 110 5000

很完美,那我们要求人数正序,待遇倒序又会发生什么呢?

1
2
3
4
5
yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3r
guge 50 3000
sohu 100 4500
baidu 100 10000
google 110 5000

咦,好像没什么变化嘛?难道r的选项没效果么?
加一行试试:

1
2
3
4
5
6
yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3
guge 50 3000
sohu 100 4500
baidu 100 10000
ali 100 50000
google 110 5000
1
2
3
4
5
6
yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3r
guge 50 3000
ali 100 50000
sohu 100 4500
baidu 100 10000
google 110 5000

第二列的确是按照数值排序了,但是第三列又没有按照数值排序了。

1
2
3
4
5
6
yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3rn
guge 50 3000
ali 100 50000
baidu 100 10000
sohu 100 4500
google 110 5000

这样第三列就正常按照数值排序了,那为什么我前面写的-n一会有用一会又没用呢?
看下man的结果:

KEYDEF is F[.C][OPTS][,F[.C][OPTS]] for start and stop position, where F is a field number and C a character position in the field; both are origin 1, and the stop position defaults to the line’s end. If neither -t nor -b is in effect, char‐acters in a field are counted from the beginning of the preceding whitespace. OPTS is one or more single-letter ordering options [bdfgiMhnRrV], which override global ordering options for that key. If no key is given, use the entire line as the key.

里面有句:如果k的域后面加上了OPTS,就会override global ordering options。原来这个地方如果在k3后面加了r之后,全局的n就被覆盖了,注意:是覆盖不是追加。
再看看这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
yu@yu-vm:~/0510$ cat test4|sort -k3    
2 baidu 100 10000
7 baidu 100 10000
4 sohu 100 4500
9 sohu 100 4500
10 ali 100 50000
5 ali 100 50000
1 google 110 5000
6 google 110 5000
3 guge 50 3000
8 guge 50 3000
yu@yu-vm:~/0510$ cat test4|sort -k3n
3 guge 50 3000
8 guge 50 3000
10 ali 100 50000
2 baidu 100 10000
4 sohu 100 4500
5 ali 100 50000
7 baidu 100 10000
9 sohu 100 4500
1 google 110 5000
6 google 110 5000

加不加n,除了影响k3的排序之外,还影响了k3相等时的排序。为了方便测试我们给每一行都加了个序号。
其实根据上面的man就可以看出来,k的正确写法是S.C,E.C,C为域的第几个字母,表示从第几个字母开始比较,默认为1;S就是我们这边的3,问题就出在E上面。如果不写E,那E就默认为最后一个域的数字,表示从3比较到行尾。但是如果k后面跟了部分opts,就会影响到E的值,将E从默认的行尾变成了S的值。
简单来说就是:-k3表示从第三列开始比较,如果第三列相等,就比较第四列,如果第四列依然相等,就比较第五列……一直到比较到行尾,如果依然相等,就返回比较第一列。
而-k3n表示从第三列开始比较,如果相等,直接就开始比较第一列。
再来看一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cat test8:
C C 1 2 1 2
C C 1 3 1 3
C C 1 31 1 31
C C 1 32 1 32
C C 1 4 1 4
C C 2 3 2 3
C C 2 4 2 4
D D 1 1 1 1
D D 1 10 1 10
D D 1 12 1 12
D D 1 2 1 2
D D 1 3 1 3
D D 1 31 1 31
R R 1 2 1 2
R R 1 20 1 20
R R 1 21 1 21
R R 1 3 1 3
R R 1 31 1 31
W W 1 1 1 1
W W 1 2 1 2
W W 1 20 1 20
W W 1 21 1 21
W W 1 23 1 23
C C 3 25 3 25
F F 1 23 1 23
A A 1 34 1 34

试试如下命令:

1
2
3
4
5
6
7
8
9
10
cat test8|sort -k3;
cat test8|sort -k3 -k4;
cat test8|sort -k3 -k4n;
cat test8|sort -k3 -k4nr;以上的命令输出的结果全部都是一样!并没有按我们预期的把第四列再去排序。不知道是设计的BUG还是什么,我的理解就是,前面的-k3就已经把k4的排序任务做掉了,所以后面虽然指定了k4的排序,但是并没有起作用。
那如何让这边只排序k3不要去管后续的呢?
从上面的结果可以看出来,加一个opts即可。
cat test8|sort -k3n -k4nr或者cat test8|sort -n -k3 -k4nr都可以。
那如果我要比较第二列,字母列,不能用-n了,怎么办呢?
cat test8|sort -k2,2 -k4nr
其中的k2,2表示我只要比较k2。

综上可知,sort使用-k时需要注意:
1)-k的比较顺序,默认情况下是从指定域一直比较到行尾再返回第一个域一直比较到指定域的前一个域;但是如果k后面接了部分影响的opts(只测试了n会影响而r不会),则比较完指定域之后就会跳到比较第一个域,再依次往下
2)-k后接的opts会覆盖全局设置的opts,如果需要指定,则必须指定全面(指定时需要视情况包含全局设置的opts,否则会影响排序结果)
3)需要比较多个域时,比较单个域时-kX写成-kX,X,以避免1)中的比较顺序带来的影响。