shell脚本sort排序详解
sort排序,在处理单个域排序时基本没有什么问题,都能正确显示我们期望的结果,但是在涉及到多个域进行排序是就有很多小细节需要注意了。
先看看示例的文档:
1 | yu@yu-vm:~/0510$ cat test4 |
第一列表示公司名称,第二列表示人数,第三列表示工资
现在按照人数进行排序下:
1 | yu@yu-vm:~/0510$ cat test4|sort -k2 |
好像不太像我们想象的那样,原因就是此处是按照字符串进行排序的,5比1大,所以50排在后面。
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 |
指定一个-n,要求以数值进行排序,OK。
这时候我们希望按照人数及待遇排序
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3 |
很完美,那我们要求人数正序,待遇倒序又会发生什么呢?
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3r |
咦,好像没什么变化嘛?难道r的选项没效果么?
加一行试试:
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3 |
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3r |
第二列的确是按照数值排序了,但是第三列又没有按照数值排序了。
1 | yu@yu-vm:~/0510$ cat test4|sort -n -k2 -k3rn |
这样第三列就正常按照数值排序了,那为什么我前面写的-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 | yu@yu-vm:~/0510$ cat test4|sort -k3 |
加不加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 | cat test8: |
试试如下命令:
1 | cat test8|sort -k3; |
综上可知,sort使用-k时需要注意:
1)-k的比较顺序,默认情况下是从指定域一直比较到行尾再返回第一个域一直比较到指定域的前一个域;但是如果k后面接了部分影响的opts(只测试了n会影响而r不会),则比较完指定域之后就会跳到比较第一个域,再依次往下
2)-k后接的opts会覆盖全局设置的opts,如果需要指定,则必须指定全面(指定时需要视情况包含全局设置的opts,否则会影响排序结果)
3)需要比较多个域时,比较单个域时-kX写成-kX,X,以避免1)中的比较顺序带来的影响。