随堂练习 文本处理三剑客 AWK(一)

文本处理三剑客之 awk

awk 工作原理和基本用法说明

awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK

有多种版本:

  AWK:原先来源于 AT & T 实验室的的AWK

  NAWK:New awk,AT & T 实验室的AWK的升级版

  GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容

gawk:模式扫描和处理语言,可以实现下面功能

  文本处理

  输出格式化的文本报表

  执行算数运算

  执行字符串操作

格式:

awk [options] 'program' var=value file…

awk [options] -f programfile var=value file…

说明:
program通常是被放在单引号中,并可以由三种部分组成

BEGIN语句块

模式匹配的通用语句块

END语句块

常见选项:

  -F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符

  -v var=value 变量赋值

Program格式:

pattern{action statements;..}

pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等

action statements:对数据进行处理,放在{}内指明,常见:print, printf

awk 工作过程

第一步:执行BEGIN{action;… }语句块中的语句

第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

第三步:当读至输入流末尾时,执行END{action;…}语句块BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块 pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块

分割符、域和记录

  由分隔符分隔的字段(列column,域field)标记$1,$2...$n称为域标识,$0为所有域,注意:和 shell中变量$符含义不同

  文件的每一行称为记录record

  如果省略action,则默认执行 print $0 的操作

常用的action分类

output statements:print,printf

Expressions:算术,比较表达式等

Compound statements:组合语句

Control statements:if, while等

input statements

awk控制语句

{ statements;… } 组合语句

if(condition) {statements;…}

if(condition) {statements;…} else {statements;…}

while(conditon) {statments;…}

do {statements;…} while(condition)

for(expr1;expr2;expr3) {statements;…}

break

continue

exit

动作 print

格式

print item1, item2, ...

说明:

逗号分隔符

输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式

如省略item,相当于print $0

固定字符符需要用“ ” 引起来,而变量和数字不需要

范例

[root@centos8 ~]# awk  '{print "hello,awk"}'

[root@centos8 ~]# seq 10 | awk '{print "hello,awk"}'
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk

[root@centos8 ~]# seq 3 | awk '{print 2*3}'
6
6
6

[root@centos8 ~]# awk -F: '{print "long"}' /etc/passwd

[root@centos8 ~]# awk -F: '{print}' /etc/passwd

[root@centos8 ~]# awk -F: '{print $0}' /etc/passwd

[root@centos8 ~]# awk -F: '{print $1,$3}' /etc/passwd

[root@centos8 ~]# awk -F: '{print $1"\t"$3}' /etc/passwd

[root@centos8 ~]# grep "^UUID" /etc/fstab | awk {'print $2,$3'}

/ xfs
/boot ext4
/data xfs
swap swap

面题:取出网站访问量最大的前3个IP

[root@centos8 ~]# awk '{print $1}' nginx.access.log | sort | uniq -c | sort -nr | head -n3

213  122.54.68.23

168  117.145.214.13

 56   223.158.167.123

[root@centos8 ~]# awk '{print $1}' access_log | sort | uniq -c | sort -nr | head
4870 172.20.116.228

3429 172.20.116.208

2834 172.20.0.222

2613 172.20.112.14

2267 172.20.0.227

2262 172.20.116.179

2259 172.20.65.65

1565 172.20.0.76

1482 172.20.0.200

1110 172.20.28.145

面试题:取出分区利用率

[root@centos8 ~]# df | awk '{print $1,$5}'
Filesystem Use%
devtmpfs 0%
tmpfs 0%
tmpfs 2%
tmpfs 0%
/dev/sda2 3%
/dev/sda3 1%
/dev/sda1 15%
tmpfs 0%

#使用扩展的正则表达式
[root@centos8 ~]# df | awk -F"[[:space:]]+|%"  '{print $5}'
Use
0
0
1
0
5
1
92
1

[root@centos8 ~]# df | awk -F'[[:space:]]+|%'  '{print $1,$5}'
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 2
tmpfs 0
/dev/sda2 3
/dev/sda3 1
/dev/sda1 15
tmpfs 0

[root@centos8 ~]# df | grep "^/dev/sd" | awk -F"[[:space:]]+|%"  '{print $5}'

3
1
15

[root@centos8 ~]# df | grep '^/dev/sd' | awk -F'[[:space:]]+|%'  '{print $1,$5}'

/dev/sda2 3
/dev/sda3 1
/dev/sda1 15

[root@centos8 ~]# df | awk -F"[[:space:]]+|%"  '/^\/dev\/sd/{print $5}'

3
1
15

[root@centos8 ~]# df | awk -F'[[:space:]]+|%'  '/^\/dev\/sd/{print $1,$5}'

/dev/sda2 3
/dev/sda3 1
/dev/sda1 15

面试题:取 ifconfig 输出结果中的IP地址

[root@centos8 ~]# ifconfig eth0 | awk '/netmask/{print $2}'

10.0.0.100

[root@centos6 ~]# ifconfig eth0 | awk -F " +|:" '/Mask/{print $4}'

10.0.0.6

[root@centos8 ~]# ifconfig eth0 | sed -nr '2s/^[0-9]+([0-9.]+) .*$/\1/p'

10.0.0.100

[root@centos6 ~]# ifconfig eth0 | sed -nr '2s/^[0-9]+([0-9.]+) .*$/\1/p'

10.0.0.6

面试题:文件host_list.log 如下格式,请提取”.longwang.com”前面的主机名部分并写入到回到该文件中

[root@centos8 ~]# cat host_list.log
1 www.longwang.com
2 blog.longwang.com
3 study.longwang.com
4 linux.longwang.com
5 python.longwang.com

[root@centos8 ~]# awk -F"[ .]"  '{print $2}' host_list.log

www
blog
study
linux
python

[root@centos8 ~]# awk -F"[ .]" '{print $2}' host_list.log >> host_list.log

[root@centos8 ~]#cat host_list.log
1 www.longwang.com
2 blog.longwang.com
3 study.longwang.com
4 linux.longwang.com
5 python.longwang.com

www
blog
study
linux
python

 

awk变量

常见的内置变量

FS:输入字段分隔符,默认为空白字符,功能相当于 -F

OFS:输出字段分隔符,默认为空白字符

RS:输入记录record分隔符,指定输入时的换行符

ORS:输出记录分隔符,输出时用指定符号代替换行符

NF:字段数量

NR:记录的编号

FNR:各文件分别计数,记录的编号

FILENAME:当前文件名

ARGC:命令行参数的个数

ARGV:数组,保存的是命令行所给定的各参数,每一个参数:ARGV[0],......

 

awk中的变量分为:内置和自定义变量

常见的内置变量

  FS:输入字段分隔符,默认为空白字符,功能相当于 -F
范例:

awk -v FS=':' '{print $1,FS,$3}' /etc/passwd

awk -v FS=":" '{print $1FS$3}' /etc/passwd

awk –F: '{print $1,$3,$7}' /etc/passwd

S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd

[root@centos8 ~]# awk -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2

[root@centos8 ~]# S=:;awk -F$S '{print $1,$3}' /etc/passwd|head -n3
root 0
bin 1
daemon 2

#-F 和 FS变量功能一样,同时使用会冲突
[root@centos8 ~]# awk -v FS=":" -F";" '{print $1FS$3}' /etc/passwd |head -n3
root:x:0:0:root:/root:/bin/bash;
bin:x:1:1:bin:/bin:/sbin/nologin;
daemon:x:2:2:daemon:/sbin:/sbin/nologin;

[root@centos8 ~]# awk -F";" -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2

  OFS:输出字段分隔符,默认为空白字符

范例

[root@centos8 ~]# awk -v FS=':'  '{print $1,$3,$7}' /etc/passwd | head -n1

root 0 /bin/bash

[root@centos8 ~]# awk -v FS=":"  -v  OFS=":"  '{print $1,$3,$7}'

/etc/passwd|head -n1
root:0:/bin/bash

  RS:输入记录record分隔符,指定输入时的换行符

范例:

awk -v RS=' ' ‘{print }’ /etc/passwd

  ORS:输出记录分隔符,输出时用指定符号代替换行符

范例

awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd

  NF:字段数量

范例

#引用变量时,变量前不需加$

[root@centos8 ~]# awk -F:  '{print NF}'  /etc/fstab

[root@centos8 ~]# awk -F:  '{print $(NF-1)}'  /etc/fstab

[root@centos8 ~]# ls /misc/cd/BaseOS/Packages/*.rpm | awk -F ":"  '{print $(NF-1)}' | sort | uniq -c

389 i686
208 noarch
1060 x86_64

面试题:接数最多的前3个IP

[root@centos8 ~]# awk -F " +|:"  '{print $(NF-2)}'  sos.log | sort | uniq -c | sort -nr | head -n3

20 223.66.64.148

16 119.23.176.118

13 182.250.65.202

[root@centos8 ~]# awk -F " +|:"  '/^ESTAB/{print $(NF-2)}' sos.log | sort | uniq -c | sort -nr | head -n3

15 223.77.34.147

10 182.202.66.23

8 116.134.156.88

[root@centos8 ~]# ss -nt | grep "^ESTAB" | awk -F"[[:space:]]+|:"  '{print $(NF-2)}'

10.0.0.1

10.0.0.100

10.0.0.1

[root@centos8 ~]# ss -nt | awk -F"[[:space:]]+|:"  '/^ESTAB/{print $(NF-2)}'

Address
10.0.0.1

[root@centos8 ~]# ss -tn | awk -F: '{print $(NF-1)}' | awk '/^[0-9]/{print $NF}' | sort | uniq -c | head -n3

范例:每十分钟检查将连接数超过100个以上的IP放入黑名单拒绝访问

[root@centos8 ~]# cat deny_dos.sh

#!/bin/bash

LINK=100

while true ;do

  ss -nt | awk -F"[[:space:]]+|:"  '/^ESTAB/{print $(NF-2)}' | sort | uniq -c | while read count ip ;do

    if [ $count -gt $LINK ]; then

      iptables -A INPUT -s $ip -j REJECT

    fi

  done

done

[root@centos8 ~]# chmod +x /root/deny_dos.sh

[root@centos8 ~]# crontab -e

[root@centos8 ~]# crontab -l

*/10 * * * * /root/deny_dos.sh

范例:

[root@centos8 ~]# cat deny_dos.sh

#!/bin/bash

IPLIST=`awk -F" +|:"  '/^ESTAB/{print $(NF-2)}' sos.log | sort | uniq -c | sort -nr | head -n3 | awk '{print $2}'`

for ip in $IPLIST;do

  iptables -A INPUT -s $ip -j REJECT

done

  NR:记录的编号

范例:

[root@centos8 ~]# awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.1.1911 (Core)

范例:取ifconfig输出结果中的IP地址

[root@centos8 ~]# ifconfig eth0 | awk '/netmask/{print $2}'
10.0.0.100

[root@centos8 ~]# ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.100

范例:

[root@centos8 ~]# awk -F: '{print NR}' /etc/passwd
1
2
3
.......
[root@centos8 ~]# awk -F: 'END{print NR}' /etc/passwd
57

[root@centos8 ~]# awk -F: 'BEGIN{print NR}' /etc/passwd
0

  FNR:各文件分别计数,记录的编号

范例:

awk '{print FNR}' /etc/fstab /etc/inittab

[root@centos8 ~]# awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
4 CentOS Linux release 8.0.1905 (Core)

[root@centos8 script40]# awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
3
1 CentOS Linux release 8.0.1905 (Core)

  FILENAME:当前文件名

范例:

[root@centos8 ~]# awk '{print FILENAME}' /etc/fstab

[root@centos8 ~]# awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/redhat-release CentOS Linux release 8.0.1905 (Core)

  ARGC:命令行参数的个数

范例:

[root@centos8 ~]# awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3

[root@centos8 ~]# awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
3

  ARGV:数组,保存的是命令行所给定的各参数,每一个参数:ARGV[0],......

范例:

[root@centos8 ~]# awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk

[root@centos8 ~]# awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue

[root@centos8 ~]# awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release

[root@centos8 ~]# awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release

 

自定义变量(区分字符大小写)
-v var=value
在program中直接定义

范例:

awk -v test='hello gawk' '{print test}' /etc/fstab

awk -v test='hello gawk' 'BEGIN{print test}'

awk 'BEGIN{test="hello,gawk";print test}'

awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd

cat awkscript

{print script,$1,$2}

awk -F: -f awkscript script="awk" /etc/passwd

posted @ 2020-07-13 16:56  空白的旋律  阅读(188)  评论(0编辑  收藏  举报