一、AWK之入门
1.AWK简介
AWK并非是一个简单的命令,他其实是一门编程语言,非常适合用来处理文本类数据。数据可以来自标准输入、外部文件,或者其他命令的输出。AWK同时支持正则表达式和用户自定函数。
2.AWK的语法格式
awk 'Pattern {Action}' filename
-其中Pattern用来指定判断条件
-{}中包含的是awk的动作,也就是awk对记录的操作
3.AWK的工作原理
step1:
AWK读取一条记录在作为输入,并将这条记录赋值给内部变量$0
step2:
记录被分隔符分隔成了多个字段,每个字段都存储到指定编号的变量中,从$1开始
step3:
对于每一条记录按照指定的Pattern进行匹配,如果匹配成功,则执行相应的Action
step4:
重复1~3,直到文件结束
4.AWK最简单入门
- AWK的处理单位是:行 –>
$0
是一个特殊符号,他表示的正是一行的内容
例1:假如有一个文件test.txt,我们想要输入文件的内容
[kiosk@foundation8 关键知识点]$ cat test.txt
huangxin100 2014/12/03
huangxin101 2015/05/06
huangxin102 2016/06/04
huangxin103 2017/03/05
[kiosk@foundation8 关键知识点]$ awk '{print $0}' test.txt
huangxin100 2014/12/03
huangxin101 2015/05/06
huangxin102 2016/06/04
huangxin103 2017/03/05
例2:指定输出列
[kiosk@foundation8 关键知识点]$ cat test.txt
huangxin100 2014/12/03
huangxin101 2015/05/06
huangxin102 2016/06/04
huangxin103 2017/03/05
[kiosk@foundation8 关键知识点]$ awk '{print $1}' test.txt
huangxin100
huangxin101
huangxin102
huangxin103
[kiosk@foundation8 关键知识点]$ awk '{print $2}' test.txt
2014/12/03
2015/05/06
2016/06/04
2017/03/05
[kiosk@foundation8 关键知识点]$ awk '{print $1,$2}' test.txt
huangxin100 2014/12/03
huangxin101 2015/05/06
huangxin102 2016/06/04
huangxin103 2017/03/05
例3:修饰表头和表尾
[kiosk@foundation8 关键知识点]$ awk 'BEGIN {print " NAME BIRTHDAY\n--------------------------"}{print $0} END {print "--------------------------"}' test.txt
NAME BIRTHDAY
--------------------------
huangxin100 2014/12/03
huangxin101 2015/05/06
huangxin102 2016/06/04
huangxin103 2017/03/05
--------------------------
例4:统计
[kiosk@foundation8 关键知识点]$ cat test.txt
huangxin100 2014/12/03 23 79
huangxin101 2015/05/06 25 56
huangxin102 2016/06/04 56 56
huangxin103 2017/03/05 89 23
[kiosk@foundation8 关键知识点]$ awk 'BEGIN {print " NAME BIRTHDAY total\n-------------------------------"}{print $1,$2,$3+$4} END {print "-------------------------------"}' test.txt
NAME BIRTHDAY total
-------------------------------
huangxin100 2014/12/03 102
huangxin101 2015/05/06 81
huangxin102 2016/06/04 112
huangxin103 2017/03/05 112
-------------------------------
例5:筛选
筛选出huangxin100的信息
[kiosk@foundation8 关键知识点]$ awk 'BEGIN {print " NAME BIRTHDAY total\n-------------------------------"} $1 ~ /huangxin100/ {print $1,$2,$3+$4} END {print "-------------------------------"}' test.txt
NAME BIRTHDAY total
-------------------------------
huangxin100 2014/12/03 102
-------------------------------
例6:像编脚本一样编awk
[kiosk@foundation8 关键知识点]$ awk -f test.awk test.txt
NAME BIRTHDAY total
-------------------------------
huangxin100 2014/12/03 102
huangxin101 2015/05/06 81
huangxin102 2016/06/04 112
huangxin103 2017/03/05 112
-------------------------------
[kiosk@foundation8 关键知识点]$ cat test.awk
BEGIN {print " NAME BIRTHDAY total\n-------------------------------"}
{print $1,$2,$3+$4}
END {print "-------------------------------"}
[kiosk@foundation8 关键知识点]$ cat test.txt
huangxin100 2014/12/03 23 79
huangxin101 2015/05/06 25 56
huangxin102 2016/06/04 56 56
huangxin103 2017/03/05 89 23
例6(+):加上环境变量,看起来更像脚本
[kiosk@foundation8 Desktop]$ cat test.awk
#!/bin/awk -f
BEGIN {print " NAME BIRTHDAY total\n-------------------------------"}
{print $1,$2,$3+$4}
END {print "-------------------------------"}
[kiosk@foundation8 Desktop]$ cat test.txt
huangxin100 2014/12/03 23 79
huangxin101 2015/05/06 25 56
huangxin102 2016/06/04 56 56
huangxin103 2017/03/05 89 23
[kiosk@foundation8 Desktop]$ ./test.awk test.txt
NAME BIRTHDAY total
-------------------------------
huangxin100 2014/12/03 102
huangxin101 2015/05/06 81
huangxin102 2016/06/04 112
huangxin103 2017/03/05 112
-------------------------------
二、AWK之多行操作
例1:只展示奇数行
[kiosk@foundation8 关键知识点]$ cat test.txt
1
2
3
4
5
6
7
8
9
[kiosk@foundation8 关键知识点]$ awk 'NR%2==0 {next} {print NR, $0}' test.txt
1 1
3 3
5 5
7 7
9 9
例2:固定行数合并
[kiosk@foundation8 关键知识点]$ cat test.txt
1
2
3
4
5
6
7
8
9
[kiosk@foundation8 关键知识点]$ awk 'NR%3!=0 {T=(T" "$0);next} {print T, $0;T=""} END {print T}' test.txt
1 2 3
4 5 6
7 8 9
例3:不定行数合并
[kiosk@foundation8 关键知识点]$ cat test.txt
xiaoming grade is
12
45
89
36
46
xiaohong grade is
13
46
79
12
23
xiaoqiang grade is
12
56
79
46
46
使用正着表达式来进行分组:/grade/
问题:没有将后面的数字分开
[kiosk@foundation8 关键知识点]$ awk 'BEGIN {T=""} /grade/ {print T; T=$0; next} {T=T""$0} END {print T}' test.txt
xiaoming grade is 1245893646
xiaohong grade is 13 46791223
xiaoqiang grade is 12 56794646
例4:合并所有行
[kiosk@foundation8 关键知识点]$ cat test.txt
one
two
three
four
five
six
seven
eight
nine
ten
[kiosk@foundation8 关键知识点]$ awk '{T=T" "$0} END {print T}' test.txt
one two three four five six seven eight nine ten
三、AWK之多文件操作
例1:多文件输出
[kiosk@foundation8 关键知识点]$ cat input1.txt
hello
[kiosk@foundation8 关键知识点]$ cat input2.txt
world
[kiosk@foundation8 关键知识点]$ awk '{print $0}' input1.txt input2.txt
hello
world
例2:两手抓两个文件
[kiosk@foundation8 关键知识点]$ cat input1.txt
hello1
world1
[kiosk@foundation8 关键知识点]$ cat input2.txt
hello2
world2
要求:抓出文件一的第一行,文件二的第二行,以及相应的名字
[kiosk@foundation8 关键知识点]$ awk 'NR==FNR&&FNR==1 {print FILENAME, $0} NR>FNR&&FNR==2 {print FILENAME,$0}' input1.txt input2.txt
input1.txt hello1
input2.txt world2
例3:多只手抓多个文件
[kiosk@foundation8 关键知识点]$ cat input1.txt
hello1
world1
[kiosk@foundation8 关键知识点]$ cat input2.txt
hello2
world2
[kiosk@foundation8 关键知识点]$ cat input3.txt
hello3
world3
!!!
要求:显示input1.txt的第一行,input2.txt的第二行,input3.txt的第三行
<方法一>
[kiosk@foundation8 关键知识点]$ awk 'ARGIND==1&&FNR==1 {print $0} ARGIND==2&&FNR==2 {print $0} ARGIND==3&&FNR==3 {print $0}' input1.txt input2.txt input3.txt
hello1
world2
!!!
<方法二>
[kiosk@foundation8 关键知识点]$ awk 'FILENAME==ARGV[1]&&FNR==1 {print $0} FILENAME==ARGV[2]&&FNR==2 {print $0} FILENAME==ARGV[3]&&FNR==3 {print $0}' input1.txt input2.txt input3.txt
hello1
world2
!!!
例四:合并两个文件
Linux系统中有两个很特殊的文件,分别为:/etc/passwd 和 /etc/shadow
/etc/passwd:
[kiosk@foundation8 关键知识点]$ head /etc/passwd --> 第二个域用x代替,存储的是账户对应的密码
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
/etc/shadow:
[root@foundation8 关键知识点]# head /etc/shadow
root:$6$oZ1JGQiQ$0lau6DEHSV81iQ54SJyjhI7s9DvAz2Ly5JVwGxMXJqDodk61DXZnF79ibX.scEeHKIe1tBTqLSCIfYV2k3AuW1::0:99999:7:::
bin:*:16925:0:99999:7:::
daemon:*:16925:0:99999:7:::
adm:*:16925:0:99999:7:::
lp:*:16925:0:99999:7:::
sync:*:16925:0:99999:7:::
shutdown:*:16925:0:99999:7:::
halt:*:16925:0:99999:7:::
mail:*:16925:0:99999:7:::
operator:*:16925:0:99999:7:::
- 我们希望用/etc/shadow文件中的密码替换掉/etc/passwd中的”x”,生成一个全新的passwd文件
[root@foundation8 关键知识点]# awk 'BEGIN {OFS=FS=":"} NR==FNR {a[$1]=$2} NR>FNR {$2=a[$1]; print} ' shadow passwd
root:$6$oZ1JGQiQ$0lau6DEHSV81iQ54SJyjhI7s9DvAz2Ly5JVwGxMXJqDodk61DXZnF79ibX.scEeHKIe1tBTqLSCIfYV2k3AuW1:0:0:root:/root:/bin/bash
bin:*:1:1:bin:/bin:/sbin/nologin
daemon:*:2:2:daemon:/sbin:/sbin/nologin
adm:*:3:4:adm:/var/adm:/sbin/nologin
lp:*:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:/sbin/nologin
operator:*:11:0:operator:/root:/sbin/nologin
[root@foundation8 关键知识点]#
例五:合并两个文件并求合
[root@foundation8 关键知识点]# cat -n 1.txt
1 56 23 46
2 56 79 13
[root@foundation8 关键知识点]# cat -n 2.txt
1 56 23 46
2 56 79 13
[root@foundation8 关键知识点]# awk '{for(i=1;i<=NF;i++) a[i]=$i; getline<"1.txt";for(i=1;i<=NF;i++) printf a[i]+$i" ";printf "\n"}' 2.txt
112 46 92
112 158 26
四、AWK之外部调用
实现awk外部调用的两种方式:
- 通过getline引用外部数据
- 通过system调用Shell中的命令
例一:getline操作文件中的困惑
1){print;getline}输出的是文件的奇数行
[kiosk@foundation8 关键知识点]$ awk '{print;getline}' test
one
three
five
2){getline;print}输出的是文件的偶数行
[kiosk@foundation8 关键知识点]$ awk '{getline;print}' test
two
four
six
3){getline;print;getline}输出的是文件的全部内容
[kiosk@foundation8 关键知识点]$ awk '{print;getline;print}' test
one
two
three
four
five
six
4){print;getline b;print}重复输出奇数行
[kiosk@foundation8 关键知识点]$ awk '{print;getline b;print}' test
one
one
three
three
five
five
[kiosk@foundation8 关键知识点]$ awk '{print;getline b;print;print b}' test
one
one
two
three
three
four
five
five
six
- 原因如下:getline获取的是下一行的内容;getline后面跟一个变量,表示获取的数据不会复制给
$0
,而会给这个变量
例2:getline操作文件的返回值
[kiosk@foundation8 关键知识点]$ cat 1.txt
56 23 46
56 79 13
[kiosk@foundation8 关键知识点]$ cat test
one
two
three
four
five
six
[kiosk@foundation8 关键知识点]$ awk '{print $0; while((getline<"1.txt")>0) print $0}' test
one
56 23 46
56 79 13
two
three
four
five
six
需要解释的几点:
1>getline的返回值:
- 1:表示正常读取一行数据
- 0:表示到了文件末尾
- -1:表示读取遇到麻烦
2>getline重定向文件时,后面必须跟字符串类型。因此,1.txt必须加双引号,否则,awk是不会认为他是文件名的
例2:用system调用Shell
[kiosk@foundation8 关键知识点]$ awk 'BEGIN { system("ls -al")}'
total 296
drwx------ 13 kiosk kiosk 8192 Jan 15 19:09 .
drwx------ 10 kiosk kiosk 16384 Jan 1 1970 ..
-rw-r--r-- 1 kiosk kiosk 18 Jan 15 18:58 1.txt
-rw-r--r-- 1 kiosk kiosk 18 Jan 15 18:58 2.txt
-rw-r--r-- 1 kiosk kiosk 9 Jan 13 23:40 callsed
drwx------ 2 kiosk kiosk 8192 Jan 13 11:09 docker
-rw-r--r-- 1 kiosk kiosk 43 Jan 14 01:02 fstab
-rw-r--r-- 1 kiosk kiosk 0 Jan 14 00:15 Git工具
-rw-r--r-- 1 kiosk kiosk 14 Jan 15 01:03 input1.txt
-rw-r--r-- 1 kiosk kiosk 14 Jan 15 01:04 input2.txt
-rw-r--r-- 1 kiosk kiosk 19 Jan 15 18:37 input3.txt
-rw-r--r-- 1 kiosk kiosk 20 Jan 13 23:46 ins.txt
注意两点:
1>awk无法直接将脚本中的数据直接输出给shell命令
2>shell命令的执行结果也无法直接输出到awk脚本中
五AWK之实战
例1:显示本机的IP
[kiosk@foundation8 关键知识点]$ ifconfig | awk '/^br/ {inter=$1;getline;print inter,$2}'
br0: 172.25.8.250
例2:统计网卡的流量
例3:查看TCP连接状态
[root@foundation8 Desktop]# netstat -nat | awk '{print $6}'| sort |uniq -c |sort -rn
10 LISTEN
1 Foreign
1 established)
例4:查找请求数排名前5名的IP地址
例5:用tcpdump嗅探80端口的访问
例5:锁定time_wait链接最多的源IP
例6:根据端口列进程
[root@foundation8 kiosk]# netstat -ntlp | grep 80 | awk '{print $7}' | cut -d/ -f1
1348
学习资源:大鹏Linux命令百篇