该系列是基于牛客Shell题库,针对具体题目进行查漏补缺,学习相应的命令。
刷题链接:牛客题霸-Shell篇。
该系列文章都放到专栏下,专栏链接为:《专栏:Shell》。欢迎关注专栏~
本文知识预告:
- 本文复习了
awk
、grep
、sort
、uniq
命令的相关用法,并且新学习了awk命令中的split()函数的用法;
- 然后给出了四种题目的解决方案。
假设netstat命令运行的结果我们存储在nowcoder.txt里,格式如下:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6160 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 172.16.56.200:41856 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49822 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49674 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:42316 172.16.34.143:3306 ESTABLISHED
tcp 0 0 172.16.56.200:44076 172.16.240.74:6379 ESTABLISHED
tcp 0 0 172.16.56.200:49656 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58248 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:50108 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41944 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:35548 100.100.32.118:80 TIME_WAIT
tcp 0 0 172.16.56.200:39024 100.100.45.106:443 TIME_WAIT
tcp 0 0 172.16.56.200:41788 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58260 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:41812 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41854 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58252 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:49586 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41754 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:50466 120.55.222.235:80 TIME_WAIT
tcp 0 0 172.16.56.200:38514 100.100.142.5:80 TIME_WAIT
tcp 0 0 172.16.56.200:49832 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:52162 100.100.30.25:80 ESTABLISHED
tcp 0 0 172.16.56.200:50372 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:50306 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49600 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41908 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:60292 100.100.142.1:80 TIME_WAIT
tcp 0 0 172.16.56.200:37650 100.100.54.133:80 TIME_WAIT
tcp 0 0 172.16.56.200:41938 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49736 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41890 172.16.34.144:3306 ESTABLISHED
udp 0 0 127.0.0.1:323 0.0.0.0:*
udp 0 0 0.0.0.0:45881 0.0.0.0:*
udp 0 0 127.0.0.53:53 0.0.0.0:*
udp 0 0 172.16.56.200:68 0.0.0.0:*
udp6 0 0 ::1:323 :::*
raw6 0 0 :::58 :::* 7
现在需要你输出每个IP的连接数,按照连接数降序排序。你的脚本应该输出
172.16.0.24 10
172.16.34.144 9
100.100.142.4 3
0.0.0.0 3
172.16.34.143 1
172.16.240.74 1
120.55.222.235 1
100.100.54.133 1
100.100.45.106 1
100.100.32.118 1
100.100.30.25 1
100.100.142.5 1
100.100.142.1 1
相关命令学习
awk
:文本和数据进行处理的编程语言
awk
命令来自于三位创始人”Alfred Aho,Peter Weinberger, Brian Kernighan “的姓氏缩写,其功能是用于对文本和数据进行处理的编程语言。使用awk
命令可以让用户自定义函数或正则表达式对文本内容进行高效管理,与sed
、grep
并称为Linux系统中的文本三剑客。
语法格式:awk 参数 文件
常用参数:
参数 |
功能 |
-F |
指定输入时用到的字段分隔符 |
-v |
自定义变量 |
-f |
从脚本中读取awk 命令 |
-m |
对val 值设置内在限制 |
常用的awk
内置变量:
awk
语法由一系列条件和动作组成,在花括号内可以有多个动作,多个动作之间用分号分隔,在多个条件和动作之间可以有若干空格,也可以没有。
变量名称 |
说明 |
FILENAME |
当前输入文档的文件名 |
FNR |
当前输入文档的当前行号,尤其当多个输入文档时有用 |
FS |
设置字段分隔符,默认为空格或制表符 |
NF |
当前记录(行)的字段(列)个数 |
NR |
输入数据流的当前记录数(行号) |
OFS |
输出字段分隔符,默认为空格 |
ORS |
输出记录分隔符,默认为换行符 |
RS |
输入记录分隔符,默认为换行符 |
awk
是一种处理文本文件的编程语言,文件的每行数据都被称为记录,默认以空格或制表符为分隔符,每条记录被分成若干字段(列),awk
每次从文件中读取一条记录。
例子:
- 仅显示指定文件中第1、2列的内容(默认以空格为间隔符):
lucky@DESKTOP-VQ8KID4:~/shell$ awk '{print $1,$2}' nowcoder.txt
#include <iostream>
using namespace
int main()
{
int a
int b
cout <<
return 0;
}
- 以冒号为间隔符,仅显示指定文件中第1列的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $1,$2}' /etc/passwd
root x
daemon x
bin x
...
tcpdump x
sshd x
landscape x
pollinate x
lucky x
/etc/passwd
文件中的内容由:
分隔开。
- 以冒号为间隔符,显示系统中所有UID号码大于500的用户信息(第3列):
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '$3>=500' /etc/passwd
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
- 仅显示指定文件中含有指定关键词
main
的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk '/main/{print}' nowcoder.txt
int main()
- 以冒号为间隔符,仅显示指定文件中最后一个字段的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ awk -F : '{print $NF}' /etc/passwd
/bin/bash
/usr/sbin/nologin
/usr/sbin/nologin
...
/usr/sbin/nologin
/bin/false
/bin/bash
- 输出行号,
NR
将所有文件的数据视为一个数据流,而FNR
则是将多个文件的数据视为独立的若干个数据流,遇到新文件时行号从1开始重新递增。
lucky@DESKTOP-VQ8KID4:~$ awk '{print NR}' first.txt three.sh
1
2
3
lucky@DESKTOP-VQ8KID4:~$ awk '{print FNR}' first.txt three.sh
1
1
2
awk
中的split()
函数
官方解释:
The awk function split(s,a,sep) splits a string s into an awk array a using the delimiter sep.
也即是:使用分隔符sep
分割字符串s
,得到的结果存入数组a
中。
注意下标从1开始。
lucky@LAPTOP-G2DIO3FV:~$ cat date
2022:06:06:23:59
lucky@LAPTOP-G2DIO3FV:~$ awk '{split($0, a, ":"); print a[1]}' date
2022
lucky@LAPTOP-G2DIO3FV:~$ awk '{split($0, a, ":"); print a[3]}' date
06
lucky@LAPTOP-G2DIO3FV:~$ awk '{split($0, a, ":"); print a[1], a[2], a[3], a[4], a[5]}' date
2022 06 06 23 59
grep
:强大的文本搜索工具
grep
来自于英文词组“global search regular expression and print out the line”的缩写,意思是用于全面搜索的正则表达式,并将结果输出。人们通常会将grep
命令与正则表达式搭配使用,参数作为搜索过程中的补充或对输出结果的筛选,命令模式十分灵活。
与之容易混淆的是egrep
命令和fgrep
命令。如果把grep
命令当作是标准搜索命令,那么egrep
则是扩展搜索命令,等价于“grep -E
”命令,支持扩展的正则表达式。而fgrep
则是快速搜索命令,等价于“grep -F
”命令,不支持正则表达式,直接按照字符串内容进行匹配。
语法格式: grep [参数] 文件
常用参数:
参数 |
功能 |
-i |
忽略大小写 |
-c |
只输出匹配行的数量 |
-l |
只列出符合匹配的文件名,不列出具体的匹配行 |
-n |
列出所有的匹配行,显示行号 |
-h |
查询多文件时不显示文件名 |
-s |
不显示不存在、没有匹配文本的错误信息 |
-v |
显示不包含匹配文本的所有行 |
-w |
匹配整词 |
-x |
匹配整行 |
-r |
递归搜索 |
-q |
禁止输出任何结果,已退出状态表示搜索是否成功 |
-b |
打印匹配行距文件头部的偏移量,以字节为单位 |
-o |
与-b 结合使用,打印匹配的词据文件头部的偏移量,以字节为单位 |
-F |
匹配固定字符串的内容 |
-E |
支持扩展的正则表达式 |
- 搜索某个文件中,包含某个关键词的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
- 搜索某个文件中,以某个关键词开头的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep ^root /etc/passwd
root:x:0:0:root:/root:/bin/bash
- 搜索多个文件中,包含某个关键词的内容:
root@DESKTOP-VQ8KID4:~# grep lucky /etc/passwd /etc/shadow
/etc/passwd:lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
/etc/shadow:lucky:$6$SBxuPYFLSnBcfbHN$OkFFnnJCpf2P4OLOnnaWXMq.xbmgL3H5aRy4nkEkk/.8VHABaKDS6MdYm3UR3TpHZplAl5HVyffI8nbLlAAoh1:19256:0:99999:7:::
- 搜索多个文件中,包含某个关键词的内容,不显示文件名称:
root@DESKTOP-VQ8KID4:~# grep -h lucky /etc/passwd /etc/shadow
lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
lucky:$6$SBxuPYFLSnBcfbHN$OkFFnnJCpf2P4OLOnnaWXMq.xbmgL3H5aRy4nkEkk/.8VHABaKDS6MdYm3UR3TpHZplAl5HVyffI8nbLlAAoh1:19256:0:99999:7:::
- 输出在某个文件中,包含某个关键词行的数量:
root@DESKTOP-VQ8KID4:~# grep -c root /etc/passwd /etc/shadow
/etc/passwd:1
/etc/shadow:1
- 搜索某个文件中,包含某个关键词位置的行号及内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -n int nowcoder.txt
3:int main()
5: int a = 10;
6: int b = 100;
- 搜索某个文件中,不包含某个关键词的内容:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -v int nowcoder.txt
#include <iostream>
using namespace std;
{
cout << "a + b:" << a + b << endl;
return 0;
}
- 搜索当前工作目录中,包含某个关键词内容的文件,未找到则提示:
root@DESKTOP-VQ8KID4:/# grep -l root *
grep: bin: Is a directory
grep: boot: Is a directory
grep: dev: Is a directory
grep: etc: Is a directory
grep: home: Is a directory
init
grep: lib: Is a directory
grep: lib32: Is a directory
...
grep: tmp: Is a directory
grep: usr: Is a directory
grep: var: Is a directory
- 搜索当前工作目录中,包含某个关键词内容的文件,未找到不提示:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -sl main *
nowcoder.txt
- 递归搜索,不仅搜索指定目录,还搜索其内子目录内是否有关键词文件:
root@DESKTOP-VQ8KID4:/# grep -srl root /etc
/etc/services
/etc/ltrace.conf
/etc/systemd/logind.conf
/etc/crontab
/etc/newt/palette.ubuntu
/etc/xattr.conf
/etc/apparmor.d/tunables/home
...
- 搜索某个文件中,精准匹配到某个关键词的内容(搜索词应与整行内容完全一样才会显示,有别于一般搜索):
lucky@DESKTOP-VQ8KID4:~/shell$ grep -x "return 0;" nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ grep -x " return 0;" nowcoder.txt
return 0;
- 判断某个文件中,是否包含某个关键词,通过返回状态值输出结果(0为包含,1为不包含),方便在Shell脚本中判断和调用:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -q return nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ echo $? # 包含
0
lucky@DESKTOP-VQ8KID4:~/shell$ grep -q returns nowcoder.txt
lucky@DESKTOP-VQ8KID4:~/shell$ echo $? # 不包含
1
- 搜索某个文件中,空行的数量:
lucky@DESKTOP-VQ8KID4:~/shell$ grep -c ^$ nowcoder.txt
0
sort
:对文件内容进行排序
sort
命令的功能是对文件内容进行排序。有时文本中的内容顺序不正确,一行行地手动修改实在太麻烦了。此时使用sort
命令就再合适不过了,它能够对文本内容进行再次排序。
语法格式:sort [参数] 文件
常用参数:
-b |
忽略每行前面开始出的空格字符 |
-c |
检查文件是否已经按照顺序排序 |
-d |
除字母、数字及空格字符外,忽略其他字符 |
-f |
将小写字母视为大写字母 |
-i |
除040至176之间的ASCII字符外,忽略其他字符 |
-m |
将几个排序号的文件进行合并 |
-M |
将前面3个字母依照月份的缩写进行排序 |
-n |
依照数值的大小排序 |
-o <输出文件> |
将排序后的结果存入制定的文件 |
-r |
以相反的顺序来排序 |
-t <分隔字符> |
指定排序时所用的栏位分隔字符 |
-k |
指定需要排序的栏位 |
参考实例
对指定的文件内容按照字母顺序进行排序:
lucky@DESKTOP-VQ8KID4:~$ cat fruits.txt
watermelon
apple
blackberry
fig
kiwi
lemon
grapefruit
pineapple
banana
orange
lucky@DESKTOP-VQ8KID4:~$ sort fruits.txt
apple
banana
blackberry
fig
grapefruit
kiwi
lemon
orange
pineapple
watermelon
对指定的文件内容按照数字大小进行排序:
lucky@DESKTOP-VQ8KID4:~$ cat num.txt
32
2
56
321
33
22
1
45
lucky@DESKTOP-VQ8KID4:~$ sort -n num.txt
1
2
22
32
33
45
56
321
以冒号:
为间隔符,对指定的文件内容按照数字大小对第3列进行排序:
lucky@DESKTOP-VQ8KID4:~$ cat /etc/passwd | sort -t : -k 3 -n
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
...
lucky:x:1000:1000:,,,:/home/lucky:/bin/bash
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
uniq
:去除文件中的重复内容行
uniq
命令来自于英文单词unique的缩写,中文译为独特的、唯一的,其功能是用于去除文件中的重复内容行。uniq
命令能够去除掉文件中相邻的重复内容行,如果两端相同内容中间夹杂了其他文本行,则需要先使用sort
命令进行排序后再去重复,这样保留下来的内容就都是唯一的了。
划重点:去除相邻重复内容行!
语法格式:uniq [参数] 文件
常用参数:
-c |
打印每行在文本中重复出现的次数 |
-d |
每个重复纪录只出现一次 |
-u |
只显示没有重复的纪录 |
参考实例
- 对指定的文件进行去重操作:
lucky@DESKTOP-VQ8KID4:~$ cat test.txt
nowcoder
nowcoder
nowcoder
to
welcome
welcome
lucky@DESKTOP-VQ8KID4:~$ uniq test.txt
nowcoder
to
welcome
- 统计相同内容行在文件中重复出现的次数:
lucky@DESKTOP-VQ8KID4:~$ uniq -c test.txt
3 nowcoder
1 to
2 welcome
- 仅显示指定文件中存在一模一样内容行的信息:
lucky@DESKTOP-VQ8KID4:~$ uniq -d test.txt
nowcoder
welcome
- 仅显示指定文件中没有存在一摸一样内容行的信息:
lucky@DESKTOP-VQ8KID4:~$ uniq -u test.txt
to
题目解决方案
方法一:grep
+awk
+sort
- 去除第一行:
lucky@LAPTOP-G2DIO3FV:~$ grep -v "Foreign Address" nowcoder.txt
tcp 0 0 0.0.0.0:6160 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 172.16.56.200:41856 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49822 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49674 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:42316 172.16.34.143:3306 ESTABLISHED
tcp 0 0 172.16.56.200:44076 172.16.240.74:6379 ESTABLISHED
tcp 0 0 172.16.56.200:49656 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58248 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:50108 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41944 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:35548 100.100.32.118:80 TIME_WAIT
tcp 0 0 172.16.56.200:39024 100.100.45.106:443 TIME_WAIT
tcp 0 0 172.16.56.200:41788 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58260 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:41812 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41854 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:58252 100.100.142.4:80 TIME_WAIT
tcp 0 0 172.16.56.200:49586 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41754 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:50466 120.55.222.235:80 TIME_WAIT
tcp 0 0 172.16.56.200:38514 100.100.142.5:80 TIME_WAIT
tcp 0 0 172.16.56.200:49832 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:52162 100.100.30.25:80 ESTABLISHED
tcp 0 0 172.16.56.200:50372 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:50306 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49600 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41908 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:60292 100.100.142.1:80 TIME_WAIT
tcp 0 0 172.16.56.200:37650 100.100.54.133:80 TIME_WAIT
tcp 0 0 172.16.56.200:41938 172.16.34.144:3306 ESTABLISHED
tcp 0 0 172.16.56.200:49736 172.16.0.24:3306 ESTABLISHED
tcp 0 0 172.16.56.200:41890 172.16.34.144:3306 ESTABLISHED
udp 0 0 127.0.0.1:323 0.0.0.0:*
udp 0 0 0.0.0.0:45881 0.0.0.0:*
udp 0 0 127.0.0.53:53 0.0.0.0:*
udp 0 0 172.16.56.200:68 0.0.0.0:*
udp6 0 0 ::1:323 :::*
raw6 0 0 :::58 :::* 7
- 筛选
tcp
,提出第五列的IP地址,利用:
作为分隔符,利用数组进行计数:
lucky@LAPTOP-G2DIO3FV:~$ grep -v "Foreign Address" nowcoder.txt | awk '$1~/tcp/{print $5}' | awk -F ":" '{arr[$1]+=1}END{for(k in arr)print(k,arr[k])}'
100.100.32.118 1
172.16.240.74 1
172.16.0.24 10
172.16.34.143 1
100.100.45.106 1
172.16.34.144 9
100.100.142.1 1
0.0.0.0 3
100.100.142.4 3
100.100.54.133 1
100.100.142.5 1
100.100.30.25 1
120.55.222.235 1
- 最后按照计数排序即可:
lucky@LAPTOP-G2DIO3FV:~$ grep -v "Foreign Address" nowcoder.txt | awk '$1~/tcp/{print $5}' | awk -F ":" '{arr[$1]+=1}END{for(k in arr)print(k,arr[k])}' | sort -nrk2
172.16.0.24 10
172.16.34.144 9
100.100.142.4 3
0.0.0.0 3
172.16.34.143 1
172.16.240.74 1
120.55.222.235 1
100.100.54.133 1
100.100.45.106 1
100.100.32.118 1
100.100.30.25 1
100.100.142.5 1
100.100.142.1 1
所以,最终的代码为:
grep -v "Foreign Address" nowcoder.txt | awk '$1~/tcp/{print $5}' | awk -F ":" '{
arr[$1]+=1
}END{
for(k in arr)
print(k,arr[k])
}' | sort -nrk2
方法二:awk
+split()
+sort
该方法中直接使用split()
函数,可以略去一些步骤,比如对于第一行的处理就不再需要了。
awk '{
if ($1 == "tcp") {
split($5, a, ":")
t[a[1]]++
}
} END {
for (i in t){
print i, t[i]
}
}' nowcoder.txt | sort -nrk2
方法三:awk
+sort
其实要解决这道题,我们要做的有两点:
- 提取出IP地址,包括筛选TCP
- 对IP地址计数
其实,关键之处就在于第一步。这个方法其实相较于前两个方法更简单。我们先给出完整代码:
awk -F "[ :]+" '/tcp/{
a[$6]++
}END{
for(i in a)
print i,a[i]
}' nowcoder.txt | sort -nrk2
这里有一个比较陌生的东东,也就是"[ :]+"
。其实这个是正则表达式,+
表示一个或多个,这里就表示一个或多个空格或冒号。
来看看下面的示例,就能清晰的知道是怎么分割的了。(注意对比原来的内容)
lucky@LAPTOP-G2DIO3FV:~$ awk -F '[ :]+' '/tcp/{print $1"---"$2"---"$3"---"$4"---"$5"---"$6}' no
wcoder.txt
tcp---0---0---0.0.0.0---6160---0.0.0.0
tcp---0---0---127.0.0.53---53---0.0.0.0
tcp---0---0---0.0.0.0---22---0.0.0.0
tcp---0---0---172.16.56.200---41856---172.16.34.144
tcp---0---0---172.16.56.200---49822---172.16.0.24
tcp---0---0---172.16.56.200---49674---172.16.0.24
tcp---0---0---172.16.56.200---42316---172.16.34.143
tcp---0---0---172.16.56.200---44076---172.16.240.74
tcp---0---0---172.16.56.200---49656---172.16.0.24
tcp---0---0---172.16.56.200---58248---100.100.142.4
tcp---0---0---172.16.56.200---50108---172.16.0.24
tcp---0---0---172.16.56.200---41944---172.16.34.144
tcp---0---0---172.16.56.200---35548---100.100.32.118
tcp---0---0---172.16.56.200---39024---100.100.45.106
tcp---0---0---172.16.56.200---41788---172.16.34.144
tcp---0---0---172.16.56.200---58260---100.100.142.4
tcp---0---0---172.16.56.200---41812---172.16.34.144
tcp---0---0---172.16.56.200---41854---172.16.34.144
tcp---0---0---172.16.56.200---58252---100.100.142.4
tcp---0---0---172.16.56.200---49586---172.16.0.24
tcp---0---0---172.16.56.200---41754---172.16.34.144
tcp---0---0---172.16.56.200---50466---120.55.222.235
tcp---0---0---172.16.56.200---38514---100.100.142.5
tcp---0---0---172.16.56.200---49832---172.16.0.24
tcp---0---0---172.16.56.200---52162---100.100.30.25
tcp---0---0---172.16.56.200---50372---172.16.0.24
tcp---0---0---172.16.56.200---50306---172.16.0.24
tcp---0---0---172.16.56.200---49600---172.16.0.24
tcp---0---0---172.16.56.200---41908---172.16.34.144
tcp---0---0---172.16.56.200---60292---100.100.142.1
tcp---0---0---172.16.56.200---37650---100.100.54.133
tcp---0---0---172.16.56.200---41938---172.16.34.144
tcp---0---0---172.16.56.200---49736---172.16.0.24
tcp---0---0---172.16.56.200---41890---172.16.34.144
方法四:awk
+sort
+uniq
思路继续打开…方法三虽然只需要两步,代码上很简单,但又不一定想得到是吧?
咱用上之前惯用套路…awk
+sort
+uniq
+sort
组合,解决这个问题就很简单了~
来,简单讲解一下步骤:
- 以
:
作为分隔符,提取出第二列,同时筛选出tcp
:
lucky@LAPTOP-G2DIO3FV:~$ awk -F ':' '/tcp/{print $2}' nowcoder.txt
6160 0.0.0.0
53 0.0.0.0
22 0.0.0.0
41856 172.16.34.144
49822 172.16.0.24
49674 172.16.0.24
42316 172.16.34.143
44076 172.16.240.74
49656 172.16.0.24
58248 100.100.142.4
50108 172.16.0.24
41944 172.16.34.144
35548 100.100.32.118
39024 100.100.45.106
41788 172.16.34.144
58260 100.100.142.4
41812 172.16.34.144
41854 172.16.34.144
58252 100.100.142.4
49586 172.16.0.24
41754 172.16.34.144
50466 120.55.222.235
38514 100.100.142.5
49832 172.16.0.24
52162 100.100.30.25
50372 172.16.0.24
50306 172.16.0.24
49600 172.16.0.24
41908 172.16.34.144
60292 100.100.142.1
37650 100.100.54.133
41938 172.16.34.144
49736 172.16.0.24
41890 172.16.34.144
- 以空格为分隔符,提取出第二列(awk命令默认的分隔符就是空格,所以不需要指定分隔符),也即是我们需要的IP地址
lucky@LAPTOP-G2DIO3FV:~$ awk -F ':' '/tcp/{print $2}' nowcoder.txt | awk '{print $2}'
0.0.0.0
0.0.0.0
0.0.0.0
172.16.34.144
172.16.0.24
172.16.0.24
172.16.34.143
172.16.240.74
172.16.0.24
100.100.142.4
172.16.0.24
172.16.34.144
100.100.32.118
100.100.45.106
172.16.34.144
100.100.142.4
172.16.34.144
172.16.34.144
100.100.142.4
172.16.0.24
172.16.34.144
120.55.222.235
100.100.142.5
172.16.0.24
100.100.30.25
172.16.0.24
172.16.0.24
172.16.0.24
172.16.34.144
100.100.142.1
100.100.54.133
172.16.34.144
172.16.0.24
172.16.34.144
看出来这两步在干嘛了吗?事实上,这两步就是方法三里面的"[ :]+"
的效果!!!
- 后面的步骤就很简单了,先排序,再降重,这是前面的题都提到过的
lucky@LAPTOP-G2DIO3FV:~$ awk -F ':' '/tcp/{print $2}' nowcoder.txt | awk '{print $2}' | sort | uniq -c
3 0.0.0.0
1 100.100.142.1
3 100.100.142.4
1 100.100.142.5
1 100.100.30.25
1 100.100.32.118
1 100.100.45.106
1 100.100.54.133
1 120.55.222.235
10 172.16.0.24
1 172.16.240.74
1 172.16.34.143
9 172.16.34.144
- 继续,注意看题目要求哈,计数要排在第二列,所以用awk交换一下顺序即可
lucky@LAPTOP-G2DIO3FV:~$ awk -F ':' '/tcp/{print $2}' nowcoder.txt | awk '{print $2}' | sort | uniq -c | awk '{print $2, $1}'
0.0.0.0 3
100.100.142.1 1
100.100.142.4 3
100.100.142.5 1
100.100.30.25 1
100.100.32.118 1
100.100.45.106 1
100.100.54.133 1
120.55.222.235 1
172.16.0.24 10
172.16.240.74 1
172.16.34.143 1
172.16.34.144 9
- 最后一步,排序即可
lucky@LAPTOP-G2DIO3FV:~$ awk -F ':' '/tcp/{print $2}' nowcoder.txt | awk '{print $2}' | sort | uniq -c | awk '{print $2, $1}' | sort -nrk2
172.16.0.24 10
172.16.34.144 9
100.100.142.4 3
0.0.0.0 3
172.16.34.143 1
172.16.240.74 1
120.55.222.235 1
100.100.54.133 1
100.100.45.106 1
100.100.32.118 1
100.100.30.25 1
100.100.142.5 1
100.100.142.1 1
故,最终代码如下:(做了一定的缩进,方便阅读)
awk -F ':' '/tcp/{
print $2
}' nowcoder.txt | awk '{
print $2
}' | sort | uniq -c | awk '{
print $2, $1
}' | sort -nrk2
这个方法步骤很多,却是最简单的,套路和前面的题差不多。