首页 > 其他 > 详细

文本处理三剑客之 awk

时间:2020-05-16 09:27:22      阅读:43      评论:0      收藏:0      [点我收藏+]

一级标题

文本处理三剑客之 awk
awk:Linux上的实现gawk,文本报告生成器

二级标题

1 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

二级标题

2 动作 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 "wang"}‘ /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@VM_0_10_centos logs]# awk ‘{print $1}‘ nginx.access.log-20200428|sort |
uniq -c |sort -nr|head -3
?5498 122.51.38.20
?2161 117.157.173.214
?953 211.159.177.120

[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}‘
5
1
92

[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}‘
5
1
92
[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.8

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

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

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

面试题:文件host_list.log 如下格式,请提取”.magedu.com”前面的主机名部分并写入到回到该文件中
[root@centos8 ~]#cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.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.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
www
blog
study
linux
python

二级标题

3 awk变量
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
[root@centos8 ~]#

#-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
[root@centos8 ~]#

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/passwd
[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)}‘ ss.log |sort |uniq -c|sort -
nr|head -n3
??12 223.88.255.148
??11 119.250.197.118
??10 183.202.63.36
[root@centos8 ~]#awk -F" +|:" ‘/^ESTAB/{print $(NF-2)}‘ ss.log |sort |uniq -
c|sort -nr|head -n3
??12 223.88.255.148
??10 183.202.63.36
??9 117.152.155.119

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

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

范例:每十分钟检查将连接数超过100个以上的IP放入黑名单拒绝访问
[root@centos8 ~]#cat deny_dos.sh
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
IPLIST=`awk -F" +|:" ‘/^ESTAB/{print $(NF-2)}‘ ss.log |sort |uniq -c|sort -
nr|head -3|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.8
[root@centos8 ~]#ifconfig eth0 | awk ‘NR==2{print $2}‘
10.0.0.8

范例:
[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
[root@centos8 ~]#

自定义变量(区分字符大小写)
-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

二级标题

4 动作 printf
printf 可以实现格式化输出
格式:
printf “FORMAT”, item1, item2, ...
说明:
    必须指定FORMAT
    不会自动换行,需要显式给出换行控制符 \n
    FORMAT中需要分别为后面每个item指定格式符
格式符:与item一一对应
    %c:显示字符的ASCII码
    %d, %i:显示十进制整数
    %e, %E:显示科学计数法数值
    %f:显示为浮点数
    %g, %G:以科学计数法或浮点形式显示数值
    %s:显示字符串
    %u:无符号整数
    %%:显示%自身

    修饰符
    #[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,如:%3.1f
    - 左对齐(默认右对齐) 如:%-15s
    + ?显示数值的正负符号 ?如:%+d

    范例:
    awk -F: ?‘{printf "%s",$1}‘ /etc/passwd
    awk -F: ?‘{printf "%s\n",$1}‘ /etc/passwd
    awk -F: ?‘{printf "%20s\n",$1}‘ /etc/passwd
    awk -F: ?‘{printf "%-20s\n",$1}‘ /etc/passwd
    awk -F: ?‘{printf "%-20s %10d\n",$1,$3}‘ /etc/passwd
    awk -F: ?‘{printf "Username: %s\n",$1}‘ /etc/passwd
    awk -F: ?‘{printf “Username: %sUID:%d\n",$1,$3}‘ /etc/passwd
    awk -F: ?‘{printf "Username: %25sUID:%d\n",$1,$3}‘ /etc/passwd
    awk -F: ?‘{printf "Username: %-25sUID:%d\n",$1,$3}‘ /etc/passwd

二级标题

5 操作符
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值

字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^=,++, --

范例:
[root@centos8 ~]#awk ‘BEGIN{i=0;print i++,i}‘
0 1
[root@centos8 ~]#awk ‘BEGIN{i=0;print ++i,i}‘
1 1

范例:
[root@centos8 ~]#awk -v n=0 ‘!n++‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@centos8 ~]#awk -v n=0 ‘!n++{print n}‘ /etc/passwd
1
[root@centos8 ~]#awk -v n=1 ‘!n++{print n}‘ /etc/passwd
[root@centos8 ~]#awk -v n=0 ‘!++n{print n}‘ /etc/passwd

[root@centos8 ~]#awk -v n=0 ‘!++n‘ /etc/passwd
[root@centos8 ~]#awk -v n=-1 ‘!++n‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash

比较操作符:
==, !=, >, >=, <, <=

范例:
[root@centos8 ~]#awk ‘NR==2‘ /etc/issue
Kernel \r on an \m

[root@centos8 ~]#awk -F: ‘$3>=1000‘ /etc/passwd
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
wang:x:1000:1000:wang:/home/wang:/bin/bash
mage:x:1001:1001::/home/mage:/bin/bash

范例:取奇,偶数行
[root@centos8 ~]#seq 10 | awk ‘NR%2==0‘
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk ‘NR%2==1‘
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk ‘NR%2!=0‘
1
3
5
7
9

模式匹配符:
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配

范例:
[root@centos8 ~]#awk -F: ‘$0 ~ /root/{print $1}‘ /etc/passwd
[root@centos8 ~]#awk -F: ‘$0 ~ "^root"{print $1}‘ /etc/passwd
[root@centos8 ~]#awk ‘$0 !~ /root/‘ ?/etc/passwd
[root@centos8 ~]#awk ‘/root/‘ ?/etc/passwd
[root@centos8 ~]#awk -F: ‘$3==0‘ ??/etc/passwd
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" ‘$0 ~ /^\/dev\/sd/{print $5}‘
5
1
92

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

逻辑操作符:
与:&&,并且关系
或:||,或者关系
非:!,取反

范例:!取反
[root@centos8 ~]#awk ‘BEGIN{print i}‘

[root@centos8 ~]#awk ‘BEGIN{print !i}‘
1
[root@centos8 ~]#awk -v i=10 ‘BEGIN{print !i}‘
0
[root@centos8 ~]#awk -v i=-3 ‘BEGIN{print !i}‘
0
[root@centos8 ~]#awk -v i=0 ‘BEGIN{print !i}‘
1
[root@centos8 ~]#awk -v i=abc ‘BEGIN{print !i}‘
0
[root@centos8 ~]#awk -v i=‘‘ ‘BEGIN{print !i}‘
1

范例:
awk -F: ?‘$3>=0 && $3<=1000 {print $1,$3}‘ /etc/passwd
awk -F: ?‘$3==0 || $3>=1000 {print $1,$3}‘ /etc/passwd
awk -F: ?‘!($3==0) {print $1,$3}‘ ??/etc/passwd
awk -F: ?‘!($3>=500) {print $1,$3}‘ /etc/passwd

条件表达式(三目表达式)
selector?if-true-expression:if-false-expression

范例:
awk -F: ‘{$3>=1000?usertype="Common User":usertype="SysUser";printf
"%-20s:%12s\n",$1,usertype}‘ ?/etc/passwd

二级标题

6 模式PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
1. 如果未指定:空模式,匹配每一行
范例:
[root@centos8 ~]#awk -F: ‘{print $1,$3}‘ /etc/passwd

2. /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
范例:
[root@centos8 ~]#awk ?‘/^UUID/{print $1}‘ ??/etc/fstab
[root@centos8 ~]#awk ?‘!/^UUID/{print $1}‘ ?/etc/fstab
[root@centos8 ~]#df | awk ‘/^\/dev\/sd/‘
/dev/sda2 ???104806400 4935924 ?99870476 ?5% /
/dev/sda3 ???52403200 ?398876 ?52004324 ?1% /data
/dev/sda1 ????999320 ?848572 ??81936 ?92% /boot

3. relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值

范例:
[root@centos8 ~]#awk ‘!1‘ /etc/passwd
[root@centos8 ~]#awk ‘!0‘ /etc/passwd
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
.......

[root@centos8 ~]#awk ‘1‘ /etc/issue
\S
Kernel \r on an \m

[root@centos8 ~]#awk ‘0‘ /etc/issue
[root@centos8 ~]#awk ‘"magedu"‘ /etc/issue
\S
Kernel \r on an \m

[root@centos8 ~]#awk ‘""‘ /etc/issue
[root@centos8 ~]#awk ‘magedu‘ /etc/issue
[root@centos8 ~]#awk ‘magedu‘ /etc/issue
[root@centos8 ~]#awk -v magedu=wang ‘magedu‘ /etc/issue
\S
Kernel \r on an \m

[root@centos8 ~]#awk -v magedu="" ‘magedu‘ /etc/issue
[root@centos8 ~]#awk -v magedu="0" ‘magedu‘ /etc/issue
[root@centos8 ~]#awk -v magedu=0 ‘magedu‘ /etc/issue

[root@centos8 ~]#awk ‘"0"‘ /etc/issue
\S
Kernel \r on an \m

[root@centos8 ~]#awk ‘0‘ /etc/issue

范例:
awk ?-F: ?‘i=1;j=1{print i,j}‘ /etc/passwd

Awk ?-F: ‘$3>=1000{print $1,$3}‘ /etc/passwd
awk ?-F: ‘$3<1000{print $1,$3}‘ /etc/passwd
awk ?-F: ‘$NF=="/bin/bash"{print $1,$NF}‘ /etc/passwd

[root@centos8 ~]#awk -F: ‘$NF=="/bin/bash"{print $1,$NF}‘ /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash

[root@centos8 ~]#awk -F: ‘$NF ~ /bash$/{print $1,$NF}‘ /etc/passwd
root /bin/bash
wang /bin/bash
mage /bin/bash

4. line ranges:行范围
不支持直接用行号,但可以使用变量NR间接指定行号
/pat1/,/pat2/ 不支持直接给出数字格式

范例:
[root@centos8 ~]#seq 10 | awk ‘NR>=3 && NR<=6‘
3
4
5
6

[root@centos8 ~]#awk ‘NR>=3 && NR<=6{print NR,$0}‘ /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync

[root@centos8 ~]#sed -n ‘3,6p‘ /etc/passwd
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

[root@centos8 ~]#awk ‘/^bin/,/^adm/‘ /etc/passwd
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

[root@centos8 ~]#sed -n ‘/^bin/,/^adm/p‘ /etc/passwd
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

5. BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次

范例
awk -F : ‘BEGIN {print "USER USERID"} {print $1":"$3} END{print "END FILE"}‘
/etc/passwd
awk -F: ‘{print "USER USERID";print $1":"$3} END{print "END FILE"}‘ /etc/passwd
awk -F: ‘BEGIN{print "USER UID \n--------------- "}{print $1,$3}‘ /etc/passwd
awk -F: ‘BEGIN{print "USER UID \n--------"}{print $1,$3}END{print
"=========="}‘ /etc/passwd

范例:
seq 10 | awk ?‘i=0‘
seq 10 | awk ?‘i=1‘
seq 10 | awk ?‘i=!i‘
seq 10 | awk ?‘{i=!i;print i}‘
seq 10 | awk ?‘!(i=!i)‘ ??????
seq 10 | awk -v i=1 ‘i=!i‘
[root@centos8 ~]#seq 10 | awk ?‘i=0‘
[root@centos8 ~]#seq 10 | awk ?‘i=1‘
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#seq 10 | awk ?‘i=1‘
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#seq 10 | awk ?‘i=0‘
[root@centos8 ~]#seq 10 | awk ?‘i=!i‘
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk ?‘!(i=!i)‘
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk -v i=1 ‘i=!i‘
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk -v i=0 ‘i=!i‘
1
3
5
7
9
[root@centos8 ~]#seq 10 | awk ?‘{i=!i;print i}‘
1
0
1
0
1
0
1
0
1
0
[root@centos8 ~]#

二级标题

7 条件判断 if-else
语法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}......else{statementN}
使用场景:对awk取得的整行或某个字段做条件判断
范例:
awk -F: ‘{if($3>=1000)print $1,$3}‘ /etc/passwd
awk -F: ‘{if($NF=="/bin/bash") print $1}‘ /etc/passwd
awk ‘{if(NF>5) print $0}‘ /etc/fstab
awk -F: ‘{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or
Sysuser: %s\n",$1}}‘ /etc/passwd
awk -F: ‘{if($3>=1000) printf "Common user: %s\n",$1; else printf "root or
Sysuser: %s\n",$1}‘ /etc/passwd

df -h|awk -F% ‘/^\/dev\/sd/{print $1}‘| awk ‘$NF>=80{print $1,$5}‘
df | awk -F"[[:space:]]+|%" ‘/^\/dev\/sd/{if($5>80)print $1,$5}‘

[root@centos8 ~]#df | awk -F‘ +|%‘ ‘/^\/dev\/sd/{if($5>=10)print $1,$5}‘
/dev/sda1 15

awk ‘BEGIN{ test=100;if(test>90){print "very good"}
else if(test>60){ print "good"}else{print "no pass"}}‘

二级标题

8 switch语句
语法:
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or
/REGEXP2/: statement2; ...; default: statementn}

二级标题

9 循环while
语法:
while (condition) {statement;…}
条件“真”,进入循环;条件“假”,退出循环
使用场景:
对一行内的多个字段逐一类似处理时使用
对数组中的各元素逐一处理时使用
示例:
#内置函数length()返回字符数,而非字节数
[root@centos8 ~]#awk ‘BEGIN{print length("hello")}‘
5
[root@centos8 ~]#awk ‘BEGIN{print length("马哥教育")}‘
4
[root@centos7 ~]#awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF){print
$i,length($i); i++}}‘ /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13

[root@centos7 ~]#awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF)
{if(length($i)>=10){print $i,length($i)}; i++}}‘ /etc/grub2.cfg
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
crashkernel=auto 16
net.ifnames=0 13

[root@centos8 ~]#awk ‘BEGIN{ total=0;i=1;while(i<=100){total+=i;i++};print
total}‘
5050

二级标题

10 循环 do-while
语法:
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
do-while循环
语法:do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
范例:
[root@centos8 ~]#awk ‘BEGIN{ total=0;i=1;do{ total+=i;i++;}while(i<=100);print
total}‘
5050

二级标题

11 循环for

语法:
for(expr1;expr2;expr3) {statement;…}

常见用法:
for(variable assignment;condition;iteration process) {for-body}

特殊用法:能够遍历数组中的元素
for(var in array) {for-body}

范例:
[root@centos8 ~]#awk ‘BEGIN{total=0;for(i=1;i<=100;i++){total+=i};print total}‘
5050

范例:
[root@centos7 ~]#awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print
$i,length($i)}}‘ /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-0-rescue-b12558570741487c9328c996e3265b09 50
root=UUID=bebb9244-bbb8-4c69-9249-54a36c75155e 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5
net.ifnames=0 13

性能比较
time (awk ‘BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}‘)
time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time (seq –s ”+” 10000|bc)

二级标题

12 continue和break
ontinue 中断本次循环
break 中断整个循环
格式:
continue [n]
break [n]

范例:
[root@centos8 ~]#awk ‘BEGIN{sum=0;for(i=1;i<=100;i++)
{if(i%2==0)continue;sum+=i}print sum}‘
2500

[root@centos8 ~]#awk ‘BEGIN{sum=0;for(i=1;i<=100;i++)
{if(i==50)break;sum+=i}print sum}‘
1225

二级标题

13 next
next 可以提前结束对本行处理而直接进入下一行处理(awk自身循环)
范例:
[root@centos8 ~]#awk -F: ‘{if($3%2!=0) next; print $1,$3}‘ /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
nobody 65534
polkitd 998
gluster 996
rtkit 172
rpc 32
chrony 994
saslauth 992
clevis 984
pegasus 66
colord 982
setroubleshoot 980
gdm 42
gnome-initial-setup 978
sshd 74
avahi 70
tcpdump 72
wang 1000

二级标题

14 数组
awk的数组为关联数组
格式
array_name[index-expression]
范例:
weekdays["mon"]="Monday"

index-expression
    利用数组,实现 k/v 功能
    可使用任意字符串;字符串要使用双引号括起来
    如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
    若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
范例:
[root@centos8 ~]#awk
‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print
weekdays["mon"]}‘
Monday

范例:
awk ‘!line[$0]++‘ dupfile
awk ‘{!line[$0]++;print $0, line[$0]}‘ dupfile

范例:判断数组索引是否存在
[root@centos8 ~]# awk ‘BEGIN{array["i"]="x"; array["j"]="y" ; print "i" in
array, "y" in array }‘
1 0
[root@centos8 ~]#awk ‘BEGIN{array["i"]="x"; array["j"]="y" ;if ("i" in array )
{print "存在"}else{print "不存在"}}‘
存在
[root@centos8 ~]#awk ‘BEGIN{array["i"]="x"; array["j"]="y" ;if ("abc" in array )
{print "存在"}else{print "不存在"}}‘
不存在

若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}

注意:var会遍历array的每个索引
范例:遍历数组
[root@centos8 ~]#awk
‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays)
{print weekdays[i]}}‘
Tuesday
Monday

[root@centos8 ~]#awk
‘BEGIN{students[1]="daizong";students[2]="junzong";students[3]="kunzong";for(x
in students){print x":"students[x]}}‘
1:daizong
2:junzong
3:kunzong

[root@centos8 ~]#awk ‘BEGIN {
a["x"] = "welcome"
a["y"] = "to"
a["z"] = "Magedu"
for (i in a) {
??print i,a[i]
}
}‘
x welcome
y to
z Magedu

[root@centos8 ~]#awk -F: ‘{user[$1]=$3}END{for(i in user){print "username:
"i,"uid: "user[i]}}‘ /etc/passwd
username: adm uid: 3
username: rpc uid: 32
username: dnsmasq uid: 985
username: radvd uid: 75
username: sync uid: 5
username: mail uid: 8
username: exim uid: 93
username: tss uid: 59
username: gluster uid: 996
username: unbound uid: 995
username: halt uid: 7

范例:显示主机的连接状态出现的次数
[root@centos8 ~]#awk ‘NR!=1{print $1}‘ ss.log |sort |uniq -c
??118 ESTAB
???1 FIN-WAIT-1
??11 LAST-ACK

[root@centos8 ~]#cat ss.log | sed -nr ‘1!s/^([^0-9]+) .*/\1/p‘|sort |uniq -c
??529 ESTAB ?
???9 LISTEN 
??128 SYN-RECV
??95 TIME-WAIT
?
[root@centos8 ~]#ss -ant | awk ‘NR!=1{state[$1]++}END{for(i in state){print
i,state[i]}}‘
SYN-RECV 128
LISTEN 9
ESTAB 529
TIME-WAIT 95

[root@centos8 ~]#netstat -tan | awk ‘/^tcp/{state[$NF]++}END{for(i in state)
{print i,state[i]}}‘
LISTEN 9
SYN_RECV 126
ESTABLISHED 523
FIN_WAIT2 40

范例:
[root@centos8 ~]#awk ‘{ip[$1]++}END{for(i in ip){print i,ip[i]}}‘
/var/log/httpd/access_log
172.20.0.200 1482
172.20.21.121 2
172.20.30.91 29
172.16.102.29 864
172.20.0.76 1565
172.20.9.9 15
172.20.1.125 463
172.20.61.11 2
172.20.73.73 198

[root@centos8 ~]#awk ‘{ip[$1]++}END{for(i in ip){print ip[i],i}}‘ access_log
|sort -nr| head -3
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
[root@centos8 ~]#awk ‘{ip[$1]++}END{for(i in ip){print i,ip[i]}}‘ access_log
|sort -k2 -nr|head -3
172.20.116.228 4870
172.20.116.208 3429
172.20.0.222 2834

范例:封掉查看访问日志中连接次数超过1000次的IP
[root@centos8 ~]#awk ‘{ip[$1]++}END{for(i in ip){if(ip[i]>=1000)
{system("iptables -A INPUT -s "i" -j REJECT")}}}‘ nginx.access.log-20200428

范例:多维数组
[root@centos8 ~]#awk ‘BEGIN{
> array[1][1]=11
> array[1][2]=12
> array[1][3]=13
> array[2][1]=21
> array[2][2]=22
> array[2][3]=23
> for (i in array)
> ??for (j in array[i])
> ????print array[i][j]
> }‘
11
12
13
21
22
23

二级标题

15 awk函数
awk 的函数分为内置和自定义函数

    15.1 常见内置函数
    数值处理:
    rand():返回0和1之间一个随机数
    srand():配合rand() 函数,生成随机数的种子
    int():返回整数
    范例
    [root@centos8 ~]#awk ‘BEGIN{srand();print rand()}‘
    0.790437
    
    [root@centos8 ~]#awk ‘BEGIN{srand();print rand()}‘
    0.283736
    [root@centos8 ~]#awk ‘BEGIN{srand();print rand()}‘
    0.948082
    [root@centos8 ~]#awk ‘BEGIN{srand();print rand()}‘
    0.371798
    
    [root@centos8 ~]#awk ‘BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100)}‘
    35
    17
    35
    95
    19
    15
    70
    54
    46
    93

    字符串处理:
    length([s]):返回指定字符串的长度
    sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
    范例:
    [root@centos8 ~]#echo "2008:08:08 08:08:08" | awk ‘sub(/:/,"-",$1)‘
    2008-08:08 08:08:08
    
    [root@centos8 ~]#echo "2008:08:08 08:08:08" | awk ‘{sub(/:/,"-",$1);print $0}‘
    2008-08:08 08:08:08

    gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
    范例:
    [root@centos8 ~]#echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,"-",$0)‘
    2008-08-08 08-08-08
    
    [root@centos8 ~]#echo "2008:08:08 08:08:08" | awk ‘{gsub(/:/,"-",$0);print $0}‘
    2008-08-08 08-08-08

    split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个
    索引值为1,第二个索引值为2,…
    范例:
    [root@centos8 ~]#netstat -tn | awk
    ‘/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}‘
    10.0.0.1 1
    10.0.0.6 1
    10.0.0.7 673

    system 函数:可以awk中调用shell命令
    空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了
    awk的变量外其他一律用""引用起来

    awk ‘BEGIN{system("hostname")}‘
    awk ‘BEGIN{score=100; system("echo your score is " score) }‘
    
    [root@centos8 ~]#netstat -tn | awk
    ‘/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){if(count[i]>=10)
    {system("iptables -A INPUT -s "i" -j REJECT")}}}‘

    15.2 自定义函数
    自定义函数格式:
    function name ( parameter, parameter, ... ) {
    ? statements
    ? return expression
    }

    范例:
    [root@centos8 ~]#cat func.awk
    function max(x,y) {
      x>y?var=x:var=y
      return var
    }
    BEGIN{print max(a,b)}
    [root@centos8 ~]#awk -v a=30 -v b=20 -f func.awk
    30

二级标题

16 awk脚本
将awk程序写成脚本,直接调用或执行
范例:
[root@centos8 ~]#cat passwd.awk
{if($3>=1000)print $1,$3}
[root@centos8 ~]#awk -F: -f passwd.awk /etc/passwd
nobody 65534
wang 1000
mage 1001

范例:
[root@centos8 ~]#cat test.awk
#!/bin/awk -f
#this is a awk script
{if($3>=1000)print $1,$3}
[root@centos8 ~]#chmod +x test.awk
[root@centos8 ~]#./test.awk -F: /etc/passwd
nobody 65534
wang 1000
mage 1001

向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile

注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v 参数,让awk在执行
BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数
范例:
[root@centos8 ~]#cat test2.awk
#!/bin/awk -f
{if($3 >=min && $3<=max)print $1,$3}
[root@centos8 ~]#chmod +x test2.awk
[root@centos8 ~]#./test2.awk -F: min=100 max=200 /etc/passwd
systemd-resolve 193
rtkit 172
pulse 171
qemu 107
usbmuxd 113
abrt 173

练习
1、文件host_list.log 如下格式,请提取”.magedu.com”前面的主机名部分并写入到回到该文件中
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
......
999 study.magedu.com

[root@centos8 ~]#awk -F"/" ‘{url[$3]++}END{for(i in url){print url[i],i}}‘url.log |sort -nr
3 www.magedu.com
2 blog.magedu.com
1 study.magedu.com
1 mail.magedu.com

文本处理三剑客之 awk

原文:https://www.cnblogs.com/zhaihongyu/p/12898679.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!