共计 6894 个字符,预计需要花费 18 分钟才能阅读完成。
sort 命令是帮我们依据不同的数据类型进行排序,其语法及常用参数格式:
sort [-bcfMnrtk][源文件][-o 输出文件]
补充说明:sort 可针对文本文件的内容,以行为单位来排序。
参 数:
-b 忽略每行前面开始出的空格字符。
-c 检查文件是否已经按照顺序排序。
-f 排序时,忽略大小写字母。
-M 将前面 3 个字母依照月份的缩写进行排序。
-n 依照数值的大小排序。
-o< 输出文件 > 将排序后的结果存入指定的文件。
-r 以相反的顺序来排序。
-t< 分隔字符 > 指定排序时所用的栏位分隔字符。
-k 选择以哪个区间进行排序。
例子:
-
根据访问 IP 统计 UV
awk ‘{print $1}’ access.log|sort | uniq -c |wc -l
注意 {print $1} 部分必须使用单引号引起来。不能使用双引号。
2. 统计访问 URL 统计 PV
awk ‘{print $7}’ access.log|wc -l
3. 查询访问最频繁的 URL
awk ‘{print $7}’ access.log|sort | uniq -c |sort -n -k 1 -r|more
4. 查询访问最频繁的 IP
awk ‘{print $1}’ access.log|sort | uniq -c |sort -n -k 1 -r|more
5. 根据时间段统计查看日志
cat access.log| sed -n ‘/14\/Mar\/2015:21/,/14\/Mar\/2015:22/p’|more
注意:时间的斜线要用反斜线“\”转义
如是 Tomcat
sed -n '/2018-02-23 23:31.*/,/2018-02-23 23:32.*/p' catalina.out|more ## 后面加 more 的好处是可以分批显示,不会一直刷屏
扩展:
# 查询关键字
sed -n '/2019-06-27 09:55.*/,/2019-06-27 13:59.*/p' laravel.log-20190628| egrep 'request_body":"{\\"mobile'
# 查询关键字上下 3 行
sed -n '/2019-06-27 09:55.*/,/2019-06-27 13:59.*/p' laravel.log-20190628| egrep -C 3 'request_body":"{\\"mobile'
1 sort 的工作原理
sort 将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按 ASCII 码值进行比较,最后将他们按升序输出。
[rocrocket@rocrocket programming]$ cat seq.txt
banana
apple
pear
orange
[rocrocket@rocrocket programming]$ sort seq.txt
apple
banana
orange
pear
2 sort 的 - u 选项
它的作用很简单,就是在输出行中去除重复行。
[rocrocket@rocrocket programming]$ cat seq.txt
banana
apple
pear
orange
pear
[rocrocket@rocrocket programming]$ sort seq.txt
apple
banana
orange
pear
pear
[rocrocket@rocrocket programming]$ sort -u seq.txt
apple
banana
orange
pear
pear 由于重复被 - u 选项无情的删除了。
3 sort 的 - r 选项
sort 默认的排序方式是升序,如果想改成降序,就加个 - r 就搞定了。
[rocrocket@rocrocket programming]$ cat number.txt
1
3
5
2
4
[rocrocket@rocrocket programming]$ sort number.txt
1
2
3
4
5
[rocrocket@rocrocket programming]$ sort -r number.txt
5
4
3
2
1
4 sort 的 - o 选项
由于 sort 默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如 sort filename > newfile。
但是,如果你想把排序结果输出到原文件中,用重定向可就不行了。
[rocrocket@rocrocket programming]$ sort -r number.txt > number.txt
[rocrocket@rocrocket programming]$ cat number.txt
[rocrocket@rocrocket programming]$
看,竟然将 number 清空了。
就在这个时候,- o 选项出现了,它成功的解决了这个问题,让你放心的将结果写入原文件。这或许也是 - o 比重定向的唯一优势所在。
[rocrocket@rocrocket programming]$ cat number.txt
1
3
5
2
4
[rocrocket@rocrocket programming]$ sort -r number.txt -o number.txt
[rocrocket@rocrocket programming]$ cat number.txt
5
4
3
2
1
5 sort 的 - n 选项
你有没有遇到过 10 比 2 小的情况。我反正遇到过。出现这种情况是由于排序程序将这些数字按字符来排序了,排序程序会先比较 1 和 2,显然 1 小,所以就将 10 放在 2 前面喽。这也是 sort 的一贯作风。
我们如果想改变这种现状,就要使用 - n 选项,来告诉 sort,“要以数值来排序”!
[rocrocket@rocrocket programming]$ cat number.txt
1
10
19
11
2
5
[rocrocket@rocrocket programming]$ sort number.txt
1
10
11
19
2
5
[rocrocket@rocrocket programming]$ sort -n number.txt
1
2
5
10
11
19
6 sort 的 - t 选项和 - k 选项
如果有一个文件的内容是这样:
[rocrocket@rocrocket programming]$ cat facebook.txt
banana:30:5.5
apple:10:2.5
pear:90:2.3
orange:20:3.4
这个文件有三列,列与列之间用冒号隔开了,第一列表示水果类型,第二列表示水果数量,第三列表示水果价格。
那么我想以水果数量来排序,也就是以第二列来排序,如何利用 sort 实现?
幸好,sort 提供了 - t 选项,后面可以设定间隔符。(是不是想起了 cut 和 paste 的 - d 选项,共鸣~~)
指定了间隔符之后,就可以用 - k 来指定列数了。
[rocrocket@rocrocket programming]$ sort -n -k 2 -t : facebook.txt
apple:10:2.5
orange:20:3.4
banana:30:5.5
pear:90:2.3
我们使用冒号作为间隔符,并针对第二列来进行数值升序排序,结果很令人满意。
7 其他的 sort 常用选项
- f 会将小写字母都转换为大写字母来进行比较,亦即忽略大小写
- c 会检查文件是否已排好序,如果乱序,则输出第一个乱序的行的相关信息,最后返回 1
- C 会检查文件是否已排好序,如果乱序,不输出内容,仅返回 1
- M 会以月份来排序,比如 JAN 小于 FEB 等等
- b 会忽略每一行前面的所有空白部分,从第一个可见字符开始比较。
有时候学习脚本,你会发现 sort 命令后面跟了一堆类似 -k1,2,或者 -k1.2 -k3.4 的东东,有些匪夷所思。今天,我们就来搞定它—- k 选项!
1 准备素材
$ cat facebook.txt
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
第一个域是公司名称,第二个域是公司人数,第三个域是员工平均工资。
2 我想让这个文件按公司的字母顺序排序,也就是按第一个域进行排序:(这个 facebook.txt 文件有三个域)
$ sort -t‘‘-k 1 facebook.txt
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500
看到了吧,就直接用 -k 1 设定就可以了。(其实此处并不严格,稍后你就会知道)
3 我想让 facebook.txt 按照公司人数排序
$ sort -n -t‘‘-k 2 facebook.txt
guge 50 3000
baidu 100 5000
sohu 100 4500
google 110 5000
不用解释,我相信你能懂。
但是,此处出现了问题,那就是 baidu 和 sohu 的公司人数相同,都是 100 人,这个时候怎么办呢?按照默认规矩,是从第一个域开始进行升序排序,因此 baidu 排在了 sohu 前面。
4 我想让 facebook.txt 按照公司人数排序,人数相同的按照员工平均工资升序排序:
$ sort -n -t‘‘-k 2 -k 3 facebook.txt
guge 50 3000
sohu 100 4500
baidu 100 5000
google 110 5000
看,我们加了一个 -k2 -k3 就解决了问题。对滴,sort 支持这种设定,就是说设定域排序的优先级,先以第 2 个域进行排序,如果相同,再以第 3 个域进行排序。(如果你愿意,可以一直这么写下去,设定很多个排序优先级)
5 我想让 facebook.txt 按照员工工资降序排序,如果员工人数相同的,则按照公司人数升序排序:(这个有点难度喽)
$ sort -n -t‘‘-k 3r -k 2 facebook.txt
baidu 100 5000
google 110 5000
sohu 100 4500
guge 50 3000
此处有使用了一些小技巧,你仔细看看,在 -k 3 后面偷偷加上了一个小写字母 r。你想想,再结合我们上一篇文章,能得到答案么?揭晓:r 和 - r 选项的作用是一样的,就是表示逆序。因为 sort 默认是按照升序排序的,所以此处需要加上 r 表示第三个域(员工平均工资)是按照降序排序。此处你还可以加上 n,就表示对这个域进行排序时,要按照数值大小进行排序,举个例子吧:
$ sort -t‘‘-k 3nr -k 2n facebook.txt
baidu 100 5000
google 110 5000
sohu 100 4500
guge 50 3000
看,我们去掉了最前面的 - n 选项,而是将它加入到了每一个 - k 选项中了。
6 - k 选项的具体语法格式
要继续往下深入的话,就不得不来点理论知识。你需要了解 - k 选项的语法格式,如下:
[FStart [ .CStart] ] [Modifier] [, [ FEnd [ .CEnd] ][Modifier] ]
这个语法格式可以被其中的逗号(“,”)分为两大部分,Start 部分和 End 部分。
先给你灌输一个思想,那就是“如果不设定 End 部分,那么就认为 End 被设定为行尾”。这个概念很重要的,但往往你不会重视它。
Start 部分也由三部分组成,其中的 Modifier 部分就是我们之前说过的类似 n 和 r 的选项部分。我们重点说说 Start 部分的 FStart 和 C.Start。
C.Start 也是可以省略的,省略的话就表示从本域的开头部分开始。之前例子中的 -k 2 和 -k 3 就是省略了 C.Start 的例子喽。
FStart.CStart,其中 FStart 就是表示使用的域,而 CStart 则表示在 FStart 域中从第几个字符开始算“排序首字符”。
同理,在 End 部分中,你可以设定 FEnd.CEnd,如果你省略.CEnd,则表示结尾到“域尾”,即本域的最后一个字符。或者,如果你将 CEnd 设定为 0(零),也是表示结尾到“域尾”。
7 突发奇想,从公司英文名称的第二个字母开始进行排序:
$ sort -t‘‘-k 1.2 facebook.txt
baidu 100 5000
sohu 100 4500
google 110 5000
guge 50 3000
看,我们使用了 -k 1.2,这就表示对第一个域的第二个字符开始到本域的最后一个字符为止的字符串进行排序。你会发现 baidu 因为第二个字母是 a 而名列榜首。sohu 和 google 第二个字符都是 o,但 sohu 的 h 在 google 的 o 前面,所以两者分别排在第二和第三。guge 只能屈居第四了。
8 又突发奇想,,只针对公司英文名称的第二个字母进行排序,如果相同的按照员工工资进行降序排序:
$ sort -t‘‘-k 1.2,1.2 -k 3,3nr facebook.txt
baidu 100 5000
google 110 5000
sohu 100 4500
guge 50 3000
由于只对第二个字母进行排序,所以我们使用了 -k 1.2,1.2 的表示方式,表示我们“只”对第二个字母进行排序。(如果你问“我使用 -k 1.2 怎么不行?”,当然不行,因为你省略了 End 部分,这就意味着你将对从第二个字母起到本域最后一个字符为止的字符串进行排序)。对于员工工资进行排 序,我们也使用了 -k 3,3,这是最准确的表述,表示我们“只”对本域进行排序,因为如果你省略了后面的 3,就变成了我们“对第 3 个域开始到最后一个域位置的内容进行排序”了。
9 在 modifier 部分还可以用到哪些选项?
可以用到 b、d、f、i、n 或 r。
其中 n 和 r 你肯定已经很熟悉了。
b 表示忽略本域的签到空白符号。
d 表示对本域按照字典顺序排序(即,只考虑空白和字母)。
f 表示对本域忽略大小写进行排序。
i 表示忽略“不可打印字符”,只针对可打印字符进行排序。(有些 ASCII 就是不可打印字符,比如 \a 是报警,\b 是退格,\n 是换行,\r 是回车等等)
10 思考思考关于 - k 和 - u 联合使用的例子:
$ cat facebook.txt
google 110 5000
baidu 100 5000
guge 50 3000
sohu 100 4500
这是最原始的 facebook.txt 文件。
$ sort -n -k 2 facebook.txt
guge 50 3000
baidu 100 5000
sohu 100 4500
google 110 5000
$ sort -n -k 2 -u facebook.txt
guge 50 3000
baidu 100 5000
google 110 5000
当设定以公司员工域进行数值排序,然后加 - u 后,sohu 一行就被删除了!原来 - u 只识别用 - k 设定的域,发现相同,就将后续相同的行都删除。
$ sort -k 1 -u facebook.txt
baidu 100 5000
google 110 5000
guge 50 3000
sohu 100 4500
$ sort -k 1.1,1.1 -u facebook.txt
baidu 100 5000
google 110 5000
sohu 100 4500
这个例子也同理,开头字符是 g 的 guge 就没有幸免于难。
$ sort -n -k 2 -k 3 -u facebook.txt
guge 50 3000
sohu 100 4500
baidu 100 5000
google 110 5000
咦!这里设置了两层排序优先级的情况下,使用 - u 就没有删除任何行。原来 - u 是会权衡所有 - k 选项,将都相同的才会删除,只要其中有一级不同都不会轻易删除的:)(不信,你可以自己加一行 sina 100 4500 试试看)
11 最诡异的排序:
$ sort -n -k 2.2,3.1 facebook.txt
guge 50 3000
baidu 100 5000
sohu 100 4500
google 110 5000
以第二个域的第二个字符开始到第三个域的第一个字符结束的部分进行排序。
第一行,会提取 0 3,第二行提取 00 5,第三行提取 00 4,第四行提取 10 5。
又因为 sort 认为 0 小于 00 小于 000 小于 0000….
因此 0 3 肯定是在第一个。10 5 肯定是在最后一个。但为什么 00 5 却在 00 4 前面呢?(你可以自己做实验思考一下。)
答案揭晓:原来“跨域的设定是个假象”,sort 只会比较第二个域的第二个字符到第二个域的最后一个字符的部分,而不会把第三个域的开头字符纳入比较范围。当发现 00 和 00 相同时,sort 就会自动比较第一个域去了。当然 baidu 在 sohu 前面了。用一个范例即可证实:
$ sort -n -k 2.2,3.1 -k 1,1r facebook.txt
guge 50 3000
sohu 100 4500
baidu 100 5000
google 110 5000
12 有时候在 sort 命令后会看到 +1 - 2 这些符号,这是什么东东?
关于这种语法,最新的 sort 是这么进行解释的:
On older systems, `sort’supports an obsolete origin-zero syntax `+POS1 [-POS2]‘for specifying sort keys. POSIX 1003.1-2001 (*note Standards conformance::) does not allow this; use `-k’instead.
原来,这种古老的表示方式已经被淘汰了,以后可以理直气壮的鄙视使用这种表示方法的脚本喽!
(为了防止古老脚本的存在,在这再说一下这种表示方法,加号表示 Start 部分,减号表示 End 部分。最最重要的一点是,这种方式方法是从 0 开始计数的,以前所说的第一个域,在此被表示为第 0 个域。以前的第 2 个字符,在此表示为第 1 个字符。明白?)
: