Featured image of post linux常用命令(一) —— sort

linux常用命令(一) —— sort

本文详解sort命令的常用方法

介绍

作用

Linux sort 命令用于将文本文件内容加以排序。

sort 可针对文本文件的内容,以行为单位来排序

注意

1、排序时,默认是按每行/每个域的首字符排序,数字的优先级要大于字符的优先级

2、不指定升序还是降序时,默认是升序

语法

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

参数

  • -b 忽略每行前面开始出的空格字符。
  • -c 检查文件是否已经按照顺序排序。
  • -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
  • -f 排序时,将小写字母视为大写字母。
  • -i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
  • -m 将几个排序好的文件进行合并。
  • -M 将前面3个字母依照月份的缩写进行排序。
  • -n 依照数值的大小排序。
  • -u 意味着是唯一的(unique),输出的结果是去完重了的。
  • -o<输出文件> 将排序后的结果存入指定的文件。
  • -r 以相反的顺序来排序。
  • -t<分隔字符> 指定排序时所用的栏位分隔字符。
  • +<起始栏位>-<结束栏位> 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
  • –help 显示帮助。
  • –version 显示版本信息。
  • [-k field1[,field2]] 按指定的列进行排序。

重点掌握

1
-t -n -o -u - k,尤其是-k。

实例

-r,逆序排序

数据准备

1
 cat salary.txt
1
2
3
4
5
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
sohu 30 1500

实验

如下所示,单独使用sort命令对文件内容进行排序,默认情况按照第一列字段内容的首字母进行升序排序

1
sort salary.txt
1
2
3
4
5
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500
sohu 30 1500

使用-r选项可按照逆序排序,但排序依据仍旧默认是第一列字段内容的首字母

1
 sort -r salary.txt
1
2
3
4
5
sohu 30 1500
sohu 100 4500
guge 50 3000
google 110 5000
baidu 100 5000

-k,指定按照某列进行排序

我们先使用salary.txt文本内容进行实验,输入以下命令

1
sort -k 2 salary.txt

观察输出结果可以发现,目前的排序结果是按照第二列字段的内容进行升序排序

1
2
3
4
5
sohu 100 4500
baidu 100 5000
google 110 5000
sohu 30 1500
guge 50 3000

这个结果其实只是一个巧合,为什么这么说呢?我们看接下来的实验

-n,按照数值大小排序

数据准备

1
 cat nums.txt
1
2
3
4
5
6
tom 10
su 15
john 2
han 20
bell 25
jom 7

我们看使用 nums.txt 文件内容的第二列进行排序的结果

1
sort -k2 nums.txt

观察实验结果,我们看到

  • 我们期望的是能够按照 nums.txt 的第二列内容进行升序排序
  • 实际情况是,出现了数字10排列在数字2之前的结果
1
2
3
4
5
6
tom 10
su 15
john 2
han 20
bell 25
jom 7

出现这个结果的原因也很简单,因为默认情况下,sort命令是将文本按照字符串进行排序的,举个例子,上述数字“10”和数字“2”,

  • 它直接将这两个数字按照字符串处理
  • 于是字符串“10”的第一个字符是“1”,而字符串“2”的第一个字符是2
  • 字符“1”比字符“2”小,因为sort只按照首字符进行排序,因此最后的结果就变成了“10”比“2”小
1
 sort -k2 -n nums.txt

上述命令的意思是,让sort将第二列内容视为数值,并以此为依据进行升序排序,观察实验结果这次是符合预期的

1
2
3
4
5
6
john 2
jom 7
tom 10
su 15
han 20
bell 25

同样的,我们也可以将其按照降序排序,如下所示

1
 sort -k2 -n -r nums.txt
1
2
3
4
5
6
bell 25
han 20
su 15
tom 10
jom 7
john 2

-t,指定字段分隔符

该选项的作用是指定字段分隔符

数据准备

1
cat data.csv
1
2
3
4
name,age,city
Alice,30,New York
Bob,25,Los Angeles
Charlie,35,Chicago

实验

我们首先不指定分隔符,想让内容按照第二列数据,也就是按照年龄进行升序排序,查看结果

1
sort -k2 -n  data.csv

可以看到,下述的输出结果也是不符合我们预期的,这又是为什么呢?

1
2
3
4
Alice,30,New York
Bob,25,Los Angeles
Charlie,35,Chicago
name,age,city

造成这个结果的原因是,

  • 当我们想使用-k选项找到第二列,它首先需要知道文本是按照什么分割符划分第一列第二列
  • 们文件内容的每一行的每一列都是按照逗号进行分割的,sort命令不知道这一点
  • 默认情况下,sort默认使用空格或者制表符作为分隔符,因此它此时找到的第二列是一个空列,也就是每一行的末尾

因此,这就是-t选项的作用,让sort知道我们的文本是按照什么分割符进行划分的,好让-k选项真正生效

重新输入命令

1
sort -t , -k2n data.csv
1
2
3
4
name,age,city
Bob,25,Los Angeles
Alice,30,New York
Charlie,35,Chicago

可以看到,这次的输出结果是符合预期的

练习,组合命令的使用

到这里,我们先写一道题,熟悉一下上述学过的命令

题目:在salary中,按薪水进行降序排列,薪资相同时,按公司人数升序排列

首先回顾一下我们的salary.txt文本内容,如下,第二列数据表示公司人数,第三列数据表示公司薪水

1
2
3
4
5
6
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
sohu 30 1500
sohu 30 2

我们直接给出答案,然后进行分析

1
sort -n -k3r -k2 salary.txt

输出结果

1
2
3
4
5
6
baidu 100 5000
google 110 5000
sohu 100 4500
guge 50 3000
sohu 30 2
sohu 30 1500

首先说明,这个输出结果是符合预期的,那么为什么要这么写

在此需要指出

  • -n是全局参数,所有指定的域(列)都有效(按数值排序)
  • 3r中的紧跟这数字的r是局部参数仅对-k 3r中r前面的数字所对应的第3个域(列)有效
  • 后面的 -k 2 没有指定降序,那么默认第2个域(列)就是升序排列的。

-o,把结果输出到指定文件

在sort排序中,如果用 > 重定向来把结果输出到源文件,源文件会被置为空。

此时,-o的作用就凸显出来了。

我们先备份一下数据进行实验

1
2
3
4
5
6
7
8
(base) jl@jin-X299X-AORUS-MASTER:~/test$ cp salary.txt s.txt
(base) jl@jin-X299X-AORUS-MASTER:~/test$ cat s.txt
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
sohu 30 1500
sohu 30 2

输入以下命令,我们期望的结果是,让文件按照第二列进行排序,并将排序的结果保存起来

1
 sort -k2n s.txt > s.txt

但现实情况是,此时的s.txt文件被置空了,也就是说,如果要把排序的结果回写到源文件,需要用-o参数,不能用重定向。

如果需要保存排序的结果,正确的命令应该是

1
sort -k2n s.txt -o s.txt

-u 去除重复行 | -k M,N消除指定域的重复行

再次回顾我们的salary.txt文件内容,我们看到,文本中有三条sohu相关的行,我们现在的需求是,我们想去除重复的行

1
2
3
4
5
6
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
sohu 30 1500
sohu 30 2

首先尝试使用下述命令

1
sort -u salary.txt

实验失败

1
2
3
4
5
6
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500
sohu 30 1500
sohu 30 2

如果我们显示指定列呢?也就是这样

1
 sort -u -k1  salary.txt

还是失败!为什么呢?

1
2
3
4
5
6
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500
sohu 30 1500
sohu 30 2

这是因为,sort排序的时候,****-u不配合其他任何参数**时,只有*完全相同的重复行*才会被消除。

另外还需要给出一个知识点,关于**-k选项,其实是有两个参数的**,这个两个参数指定了一个范围

-K M,N

  • M的意思是,从哪一列开始的第一个字符作为比较的依据;N表示截止到哪一列的最后一个字符比较结束。

  • M,N是一个(域的)范围,如果这个M,N结合-u使用。那么-u的比较范围就是第M列的第一个字符到第N列最后一个字符之间的这段内容。

  • 如果数字N被省略,那么-u比较的范围就是从M域开始,一直到每行的最后一个域的最后一个字符。

因此,正确的命令应该如下,这条命令是说,从第一列的第一个字符开始,到第一列的最后一个字符进行检查,如果发现重复就去重

1
sort -u -k 1,1 salary.txt
1
2
3
4
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500

-k 的高级用法-k1.2,3.5

通过上一案例的学习,对-k M,N有了一定了解,接下来的内容相对会比较容易理解一些。

理论知识点:

如果抛开M,N之间的逗号,单独说这个逗点

  • -k 1.2 表示第1个列的第二个字符
  • -k 2.3 表示从第2个列的第三个字符。

案例:仅仅按工资表中第一列的第二个字符升序排列

错误示范

1
sort -k 1.2  salary.txt
1
2
3
4
5
6
baidu 100 5000
sohu 100 4500
sohu 30 1500
sohu 30 2
google 110 5000
guge 50 3000

正确示范

1
sort -k 1.2,1.2  salary.txt
1
2
3
4
5
6
baidu 100 5000
google 110 5000
sohu 100 4500
sohu 30 1500
sohu 30 2
guge 50 3000

解析

  • -k1.2,1.2 仅仅且只按照第一个域的第二个字母进行排序,不会再按其他字符进行排序。
  • -k1.2 先按照第一个域的第二个字母进行排序,第二个字母如果一样,再按照第二个字母后面的字母进行排序,依次类推,直到行尾最后一个字符。也就是说:google 和 sohu的第二个字母都是o,就开始看第三个字母,显然第三个字母h应该排在o的前面。
网站已运行
发表了17篇文章 · 总计 118,129字