起因
之前只知道sort命令可以对文本排序,用选项-t指定分隔符,用-k指定排序字段,用-n指定字段为数字。但是由于实战机会较少,真正操练起来的时候,发现捉襟见肘,可以参见下面几个情景:
- 以数字大小对第一个域排序(基础)
- 以字符顺序对第一个域排序(基础)
- 以字符顺序对第一个域排序,但是只考虑第3个字符到10个字符
- 以数字大小对第一个域排序,相同则以数字大小对第二个域排序
- 以数字大小对第一个域排序,相同则以字符大小对第二个域排序
sort的规则
- sort的-k选项,会被局部选项和全局选项影响,局部选项覆盖全局选项,局部选项是跟在-k后面的选项,其余的为全局选项。
- 在不指定结束域的情况想,以数字排序,仅按指定的域排序,以字符串排序,则是指定域到行尾。
- 在指定域上的值相等的情况下,以字符顺序排序整行。
- 以数字排序时,提取域的前缀数字,处理为十进制,遇到非数字结束,所以域123abc的整数值为123。最好不要使用跨域数字排序,有个巨坑,最后再讲。
- 以字符串排序时,前缀相同的串,长度大的比较大。
下面将从这几个例子来分解sort命令
sort细节
平时我们用的sort命令的-k选项,其实是简写的方式,其完整的命令如下:
sort -k [FStart[.CStart]] [Modifier][, [FEnd[.CEnd]] [Modifier]] input.txt
sort -k 3.1,3.2n input.txt
上面的例子中的3.1,3.3n,各部分对应的值如下,其中,FStart就是要排序的起始域,CStart是起始域的第几个字符,FEnd是要排序的结束域,CEnd是结束域的第几个字符,Modifier是该排序选项的附加选项。即:对第3个域的第1到第3个字符进行数字排序。所以通常情况下的-k3则是,对第三个域到行尾进行字符顺序排序。
FStart=3
CStart=1
FEnd=3
CEnd=3
Modifier=n
例子:
- 对第一个字段字符排序
- 对第一个字段排序,但从第二个字符开始
- 对第二个字符数字排序
- 对第二个字段字符排序
所以,以下的意思是这样的
-k 7 #对第7列到行尾进行字符串排序
-k 7,8 #对第7列到第8列进行字符串排序
-k 7n #对第7列进行数字排序
-k 7,8n #对第7列到第8列进行数字排序
# 以上如果完全相等,则把 整行按字符串排序
后记
在使用时请注意几个点
- FStart必须小于等于EStart
- 如果不指定EStart,则从FStart到行尾,对字符排序和数字排序都遵守这个规则。但是数字排序就有个坑在这里:如果指定的分隔符不是逗号(,)那么跨域数字排序就没有跨域效果,栗子如下:
# 数据文件input.txt内容如下
a:100:400
b:100:300
c:10:3000
d:20:400
d:20:4000
sort -k2,3n -t':' input.txt
从上面结果可以看出,非逗号数字排序在跨域排序时,仅按起始域排序,在起始域相同的情况下,按整行字符顺序再次排序。而不是按后续域排序,从a:100:400和b:100:300的排序位置可以看出。
如果上述文件内容不变,仅把分隔符改为逗号(,),再看结果。
未曾改变数据,只改变了分隔符,结果大变。在这里我只能推测sort排序的数字处理方式如下:
- 提取指定域的内容,包括分隔符。
- 从左到右处理数字,同时忽略所有的逗号(可能因为有3位分数字的书写方式,1,234,567,仅猜测,我现在仅发现用逗号做分隔符的时候有这个现象),遇到非数字结束。
- 按上述步骤所得数字排序,如果相等则对整行字符排序。
再来看个例子:
上面这个例子可以说明,-k选项在不指定结束域时,是默认到行尾的。所以在数字排序的时候提取的是第二个域到行尾,包括分隔符(即:20,4,0,0,0),处理时忽略逗号,于是20,4,0,0,0的值实际上是204000。
如果仅指定某一个域进行数字排序,请按上面这种写法。