Linux常用命令--文本排序和去重相关命令

摘要

  • 文本的排序、去重和统计行数等相关命令,如sort、uniq、wc等等

  • 本文基于CentOS8(x86_64)

sort

  • sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们排序输出,默认升序。

sort基本用法

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
28
29
30
31
32
33
# 文件内容按ASCII码值进行比较后升序输出
sort file

# 忽略大小写
sort -f file

# -u去重
sort -u file

# -r降序
sort -r file

# -o结果输出到文件,类似于重定向 > ,但是比重定向强的一点是可以输出到源文件
sort file -o newfile

# -n 按数字大小排序,默认按字符比较,所以10比2小,此时可以加上 -n 来告诉sort要以数值来排序
sort -n file

# -M 会以月份来排序,比如JAN小于FEB
sort -M file

# -b 会忽略每一行前面的所有空白部分,从第一个可见字符开始比较
sort -b file

# -c 检查文件是否已经排好序,如果乱序,则输出第一个乱序的行的相关信息,$?值为1
sort -c file

# -C 检查文件是否已经排好序,如果乱序,则不输出任何内容,$?值为1
sort -C file

# 还有一些其它参数
-d 只考虑空白区域和字母字
-i 只针对可打印字符进行排序,有些ASCII就是不可打印字符,比如\n是换行,\r是回车等等

sort高级用法

  • 上面结束的sort用法都是从每行的第一个字符开始比较,如果文本可以被分隔为一列一列的内容,我们想按某一列进行排序该如何处理呢?

  • 为了说明这个用法,我准备了一份文件

1
2
3
4
5
6
7
$ cat file
tom,68,9.1
jack,71,18.7
alex,68,9.8
bar,100,30.6
foo,20,1.2
rucy,100,20.5
  • 以第二列进行排序,并按数字大小排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -t 分隔符,-k 排序的列号
$ sort -n -t "," -k 2 file
foo,20,1.2
tom,68,9.1
alex,68,9.8
jack,71,18.7
rucy,100,20.5
bar,100,30.6

# 这里 -n 可以写到 -k中
sort -t "," -k 2n file

# 也可以将 -r 写到 -k中
sort -t "," -k 2nr file
  • 以第一列的第二个字符进行排序

1
2
3
4
5
6
7
8
# 这里 -k 1.2,表示按第一列的第二个字符排序
$ sort -t "," -k 1.2 file
jack,71,18.7
bar,100,30.6
alex,68,9.8
tom,68,9.1
foo,20,1.2
rucy,100,20.5

小贴士

  • -k 的语法格式为[ FStart [ .CStart ] ] [ Modifier ] [ , [ FEnd [ .CEnd ] ][ Modifier ] ]
  • 这个语法格式可以被其中的逗号(“,”)分为两大部分,Start部分和End部分。
  • Start部分也由三部分组成,其中的Modifier部分就是我们之前说过的类似n和r的选项部分,比如-k 2nrb、d、f、i、n 或 r都可以用在Modifier部分。
  • FStart就是表示使用的域,而CStart则表示在FStart域中从第几个字符开始算“排序首字符”,CStart也是可以省略的,省略的话就表示从本域的开头部分开始。
  • 之前例子中的 -k 2 就是省略了CStart而只有FStart,而-k 1.2其中的 1 就是FStart,.2 就是CStart。
  • End的部分的组成同Start。
  • Start用于表示从第几个域的第几个字符开始,End用于表示到第几个域的第几个字符结束,如果不设定End部分,那么就认为End被设定为行尾。
  • 先按第二列升序排序,第二列相同则按第三列降序排序

1
2
3
4
5
6
7
8
9
10
# 看了上面的小贴士,应该可以理解这里的含义
# -k 2,2n 表示从第二个域开始到第二个域结束并按数字升序排序,
# -k 3,3nr 表示从第三个域开始到第三个域结束并按数字降序排序,
$ sort -t "," -k 2,2n -k 3,3nr file
foo,20,1.2
alex,68,9.8
tom,68,9.1
jack,71,18.7
bar,100,30.6
rucy,100,20.5
  • -k-u 同时使用要注意,-u 去重时比较的是 -k 指定的区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 此时比较的是从第二个域到行尾是否重复,所以没有可以去掉的行
$ sort -t "," -k 2n -u file
foo,20,1.2
tom,68,9.1
alex,68,9.8
jack,71,18.7
rucy,100,20.5
bar,100,30.6

# 此时比较的仅仅是第二个域,所以第二列重复的行会被去重
$ sort -t "," -k 2,2n -u file
foo,20,1.2
tom,68,9.1
jack,71,18.7
bar,100,30.6

uniq

  • uniq命令用于报告或忽略文件中的重复行,一般与sort命令结合使用

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
$ cat file
alex; 68; 98
barr;hello; test
barr;hello; test
fooo;loveable;s
jack; 71; 87
jack; 71; 87
mytest; Mark; Percent
tom; 69; 91

$ sort file | uniq
alex; 68; 98
barr;hello; test
fooo;loveable;s
jack; 71; 87
mytest; Mark; Percent
tom; 69; 91

# -c,--count:在每列旁边显示该行重复出现的次数
$ sort file | uniq -c
1 alex; 68; 98
2 barr;hello; test
1 fooo;loveable;s
2 jack; 71; 87
1 mytest; Mark; Percent
1 tom; 69; 91

# -d,--repeated:仅显示重复出现的行
$ sort file | uniq -d
barr;hello; test
jack; 71; 87

# -D, --all-repeated[=delimit-method],打印重复行的所有行。
# 其中 delimit-method 表示对重复行集合的分隔方式,有三种取值,分别为none、prepend和separate。
# 其中none表示不进行分隔,为默认选项,uniq -D等同于uniq --all-repeated=none;prepend表示在每一个重复行集合前面插入一个空行;separate表示在每个重复行集合间插入一个空行。
$ sort file | uniq -D
barr;hello; test
barr;hello; test
jack; 71; 87
jack; 71; 87

$ sort file | uniq --all-repeated=separate
barr;hello; test
barr;hello; test

jack; 71; 87
jack; 71; 87



# -u,--unique:只显示唯一的行,即出现次数等于1的行
$ sort file | uniq -u
alex; 68; 98
fooo;loveable;s
mytest; Mark; Percent
tom; 69; 91

# 其它参数
-f, --skip-fields=N
忽略前N个字段。字段由空白字符(空格符、Tab)分隔。如果您的文档的行被编号,并且您希望比较行中除行号之外的所有内容。如果指定了选项 -f 1,那么下面相邻的两行:
1 这是一条线
2 这是一条线
将被认为是相同的。如果没有指定 -f 1 选项,它们将被认为是不同的。
-i, --ignore-case
忽略大小写字符的不同。
-s, --skip-chars=N
跳过前面N个字符不比较。
-w, --check-chars=N
指定每行要比较的前N个字符数。

wc

  • wc(word count)命令用于统计文件字节、字符、单词与行的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -l, --lines 统计行数,在统计记录数时,很常用
$ wc -l /etc/passwd
29 /etc/passwd

# -w, --words 统计单词出现次数
$ wc -w /etc/passwd
48 /etc/passwd

# -c, --bytes 统计文件的字节数
$ wc -c /etc/passwd
1387

# -m, --chars 统计文件的字符数,如果是 ASCII、Latin-1 等单字节编码的字符,字符数等于字节数
$ wc -m /etc/passwd
1387

# -L, --max-line-length 显示文件中最长行的字符数
$ wc -L /etc/passwd
85 /etc/passwd