本次实验将介绍 Linux 命令中 sort、uniq 和 join 命令的用法。
课程使用的实验环境为 Ubuntu Linux 14.04 64 位版本。实验中会用到程序:
同文本文件打交道时,总避不开排序,那是因为对于文本处理任务而言,排序(sort)可以起到不小的作用。sort 命令能够帮助我们对文本文件和 stdin 进行排序操作。通常,它会结合其他命令来生成所需要的输出。
(1)命令格式
sort [选项] [文件名]
(2)常用参数
参数 | 描述 |
---|---|
-n | 基于字符串的长度来排序,使用此选项允许根据数字值排序,而不是字母值 |
-k | 指定排序关键字 |
-b | 默认情况下,对整行进行排序,从每行的第一个字符开始。这个选项导致 sort 程序忽略每行开头的空格,从第一个非空白字符开始排序 |
-m | 只合并多个输入文件 |
-r | 按相反顺序排序,结果按照降序排列,而不是升序 |
-t | 自定义分隔符,默认为制表符 |
(3)常用范例
例一:列出/usr/share/目录下使用空间最多的前 10 个目录文件,可以使用如下命令:
du -s /usr/share/* | sort -nr | head -10
du -s /usr/share/* 命令显示/usr/share/目录下所有文件和目录的磁盘使用空间,目录包含目录下的子目录和文件
例二:ls 命令能显示目录下文件的详细信息,包含空间使用大小,但与 du 命令不同的是,ls 命令不计算目录下的子目录和文件的大小。ls 显示格式如下:
-rwxrwxrwx 1 root root 542 11 月 29 test.php
现在想要对 ls 命令输出信息中的空间使用大小字段进行排序,可以使用如下命令:
ls -l /usr/bin/ | sort -nr -k 5 | head -10
例三:首先来看下下面的例子:
由于 11 由 1 开始,比 5 小,所以排在 5 的前面。这时排序可以通过自定义排序字段来排序。使用下面的命令就可以解决。
sort -k 1,1 -k 2n data.txt
第一个-k 选项指明只对第一个字段排序,1,1 意味着“始于并且结束于第一个字段”。 第二个-k 选项 2n 表示对第二个字段按数值排序。 还有一种格式,如-k 3.4n,表示始于第三个字段的第四个字符,按数值排序。
-k 选项的语法格式如下:
[ FStart [ .CStart ] ] [ Modifier ] [ , [ FEnd [ .CEnd ] ][ Modifier ] ]
这个语法格式可以被其中的逗号(“,”)分为两大部分,Start 部分和 End 部分。
先给你灌输一个思想,那就是“如果不设定 End 部分,那么就认为 End 被设定为行尾”。这个概念很重要的,但往往你不会重视它。
Start 部分也由三部分组成,其中的 Modifier 部分就是类似 n 和 r 的选项部分。我们重点说说 Start 部分的 FStart 和 CStart。 FStart.CStart,其中 FStart 就是表示使用的域,而 CStart 则表示在 FStart 域中从第几个字符开始算“排序首字符”。CStart 是可以省略的,省略的话就表示从本域的开头部分开始。之前例子中的-k 5 就是省略了 CStart 的例子。
同理,在 End 部分中,你可以设定 FEnd.CEnd,如果你省略.CEnd,则表示结尾到“域尾”,即本域的最后一个字符。或者,如果你将 CEnd 设定为 0(零),也是表示结尾到“域尾”。
uniq 命令经常和 sort 命令结合在一起使用。uniq 从标准输入或单个文件名参数接受数据有序列表,默认情况下,从数据列表中删除任何重复行。
uniq 只能用于排过序的数据输入,因此,uniq 要么使用管道,要么将排过序的文件作为输入,并总是以这种方式与 sort 命令结合起来使用。
uniq 命令是 unique 的缩写。
(1)命令格式
uniq [选项] [文件名]
(2)常用参数
参数 | 描述 |
---|---|
-c | 在每行前加上表示相应行目出现次数的前缀编号 |
-d | 只输出重复的行 |
-u | 只显示唯一的行 |
-D | 显示所有重复的行 |
-f | 比较时跳过前 n 列 |
-i | 在比较的时候不区分大小写 |
-s | 比较时跳过前 n 个字符 |
-w | 对每行第 n 个字符以后的内容不作对照 |
(3)常用范例
例一:找出/bin 目录和/usr/bin 目录下所有相同的命令,可以使用如下命令:
ls /bin /usr/bin | sort | uniq -d
例二:现有文件内容如下,红色方框里的内容表示区号,现在要统计出各个区号的总人数。
实现思路:首先按区号对每行信息排序,然后使用 uniq 命令对区号进行重复行统计。使用命令如下:
sort -k 4.1n,4.1n student.txt | uniq -c -f 3 -w 2
sort -k 4.1n,4.1n 表示对第四个字段的第一个字符按数值排序。
uniq -c -f 3 -w 2 中-f 3 表示跳过前三列的比较,那么现在只剩下最后一列,-w 2 表示第 2 个字符后的内容不做比较,为什么是 2 呢,因为跳过前三列时并没有跳过最后一列前面的空格分隔符,区号前都还有一个空格。
join 命令类似于 paste,它会往文件中添加列,但是它使用了独特的方法来完成。一个 join 操作通常与关系型数据库有关联,在关系型数据库中来自多个享有共同关键域的表格的数据结合起来,得到一个期望的结果。这个 join 命令执行相同的操作,它把来自于多个基于共享关键域的文件的数据结合起来。
通俗地说,就是将两个文件中指定栏位相同的行连接起来,即按照两个文件中共同拥有的某一列,将对应的行拼接成一行。
(1)命令格式
join [选项] 文件 1 文件 2
(2)常用参数
参数 | 描述 |
---|---|
-j FIELD | 等同于 -1 FIELD -2 FIELD,-j 指定一个域作为匹配字段 |
-1 FIELD | 以 file1 中 FIELD 字段进行匹配 |
-2 FIELD | 以 file2 中 FIELD 字段进行匹配 |
-t | 自定义分隔符,默认为制表符 |
(3)常用范例
例一:将两个文件中的第一个字段作为匹配字段,连接两个文件,可以使用如下命令:
join a.txt b.txt
例二:指定两个文件的第三个字段为匹配字段,连接两个文件,可以使用如下命令:
join -1 3 -2 3 c.txt d.txt
从上面的结果可以看到,一开始对 a.txt 和 b.txt 文件内容执行 join 命令时报错,这是因为 join 命令跟 uniq 命令一样,只能用于排过序的数据。
本课程部分内容参考博文每天一个Linux命令,感谢作者peida提供的优质教程。