文本分析工具 awk
awkawk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk是一个报告(表格)生成器,拥有强大的文本格式化能力,相当于把一些文本整理成表的样子,然后再展示出来。
awk是由 Alfred Aho,Peter Weinberger和brian Kernighan三个人创造的,由三个人的姓氏首字母组成的。 awk 早期是在unix上实现的,所以我们在linux的所使用的awk其实是gawk,也就是GNU awk
总结文本三剑客:
grep : 更适合单纯的查找或匹配文本
sed:更适合编辑匹配到的文本
awk:适合格式化文本,对文本进行较复杂格式处理
which awk
/usr/bin/awk
ll /usr/bin/awk/
usr/bin/awk -> gawk 真正的主程序
awk 属于外部命令基本语法:
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
awk [options] 'BEGIN{action;… }pattern{action;… }END{action;… }' file ... awk
程序可由: BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成
选项: -F "分隔符" 指明输入时用到的字段分隔符
-v var=value 变量赋值
pattern就是所说的模式,做过滤处理
awk的特殊模式:BEGIN 和 END
BEGIN :指定了处理文本之前需要执行的操作【变量初始化,打印表头】
END:指定了处理完所有行之后,所执行的操作
#标准输入输出用管道传给AWK 【读入三行,输出三行】
[root@centos6 data]# cat /etc/issue
1 CentOS release 6.10 (Final)
2 kernel \r on an \m
3
[root@centos6 data]# cat /etc/issue|awk '{print "hello linux"}'
1 hello linux
2 hello linux
3 hello linux
#BEGIN表示读入文件之前执行
awk 'BEGIN{print "hello linux"}' 与文件无关,只打印hello linux
#BEGIN制作表头
df | grep '^\/dev\/sd'|awk 'BEGIN{print "device use"}{print $1,$5}' |tr -d %
device use
/dev/sda2 5
/dev/sda1 4
/dev/sda3 1
print 和printf
print:用逗号隔开,可以打印字符串,数字,变量,表达式
awk '{print "hello linux"}'
getent passwd|awk -F: '{print $0}'
awk -F: '{print $1}' /etc/passwd
awk -F: '{print $0}' /etc/passwd
awk -F : '{print $1,$3}' /etc/passwd
awk -F : '{print $1 "\t" $3}' /etc/passwd #"\t"表示TAB键
printf :指定format,不能自动换行
格式符:
%c: 显示字符的ASCII码
%d: 显示十进制整数
%e: 显示科学计数法数值
%f: 显示为浮点数
%g,%G:以科学计数法或浮点形式显示数值
%s: 显示字符
%%: 显示%自身
修饰符
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
- 左对齐(默认右对齐) %-15s
+ 显示数值的正负符号 %+d
awk -F: '{prntf "%s",%1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd
awk变量:
内置变量和自定义变量
awk内置变量
内置在awk内部的变量
-v var=value 变量赋值,每个-v跟一个变量
#FS:输入字段分隔符,默认为空白字符
awk -v FS=':' '{print $1,FS,$3}' /ect/passwd
#OFS:输出字段分隔符,默认为空白字符
awk -v OFS='+++' '{print $1,OFS,$3}' /etc/passwd
#RS:输入分隔符“行” 可以什么作为分隔符符
cat f1.txt
a,b,c
d,e;xx
zz;1,2,3
awk -F, '{print $1}' f1.txt
awk -v RS=';' '{print $1,RS,$3}' f1.txt
#ORS:输出行的换行符
awk -v ORS=':' '{print $1,ORS,$3}' /etc/passwd
#NR:记录行号,每一行的行号
awk '{print NR,$0}' /etc/issue
1 CentOS release 6.10 (Final)
2 Kernel \r on an \m
3
#NF:字段数量 有几列 NF=$7 $(NF-1)倒数第二列`在这里插入代码片`
awk -F: '{print NF}' /etc/passwd
7
#FNR:分别记录多个文件的行号
awk -F: '{print FNR,$1"\t"$3}' /etc/passwd /etc/group
#FILENAME:当前的文件名
awk -F: '{print FNR,FILEANME,$1,$3}' /etc/passwd /etc/group
#ARGV :表示一个数组,数组中保存的是命令行所给定的参数
awk 'BEGIN{print "aaa",ARGV[1]}' test test1
aaa test
awk 'BEGIN{print "aaa",ARGV[2]}' test test1
aaa test1
#ARGC:参数的数量,可理解为数组的长度
awk 'BEGIN{print "aaa",ARGV[0],ARGV[1],ARGV[2],ARGC}' test1 test2 test3 test4
aaa awk test1 test2 5
awk自定义变量
用户定义的变量
#变量名区分大小写
awk -v myVar="testVar" 'BEGIN{print myVar}'
#在program中直接定义
awk 'BEGIN{myvar="ttt";print myvar}'
#使用awk取出磁盘利用率
df | grep "^\/dev\/sd" |awk -F" +|%" '{print $1 "\t" $5}'
df | grep "^\/dev\/sd" |awk -v FS" +|%" '{print $1 "\t" $5}'
#取出远程主机IP地址
ss -nt |grep "^ESTAB" |awk -F" +|:" '{print $6}'
ss -nt|awk -F ' +|:' 'NR!=1{print $6}'
ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}'
#把IP次数超过3次的扔进防火墙
for ip in `ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}' |sort |uniq -c|awk '$1>=3{print $2}'`;do iptables -A INPUT -s $ip -j REJECT;done
ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}' |sort |uniq -c|awk '$1>=3{print $2}'|while read ip;do iptables -A INPUT -s $ip -j REJECT;done
#取出文本域名
cat > test.txt <<EOF
1 https://www.baidu.com/index.html
2 https://news.sina.com.cn
3 https://mp3.baidu.com/1.mp3
4 https://map.baidu.com.cn
EOF
awk -F"/" '{print $3}' test.txt
www.baidu.com/index.html
news.sina.com.cn
mp3.baidu.com/1.mp3
map.baidu.com.cn
awk操作符:
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
- x:转换为负数
+ x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=: 右边赋值给左边
+=:先加,再赋值
-=:先减,再赋值
*=:先乘,再赋值
/=:先除,再赋值
%=:先取余,再赋值
^=:先幂运算,再赋值
++:递增操作
–:递减操作
==:判断相等;
!=:判断不等;
>:判断大于;
>=:判断大于等于;
<:判断小于;
<=:判断小于等于
~: 左边是否和右边匹配,包含
!~:是否不匹配
awk '$0 ~/root/' /etc/passwd #打印包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
awk '$0 ~ /root/{print $0}' /etc/passwd #打印包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
awk '$0 ~"root"' /etc/passwd #打印包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
awk '$0 ~"^root"' /etc/passwd #打印root开头的行
root:x:0:0:root:/root:/bin/bash
awk 'NR==2' /etc/passwd #打印第二行
bin:x:1:1:bin:/bin:/sbin/nologin
#取出IP地址 注意centos6和7有区别
[root@centos6]# ifconfig eth0|awk -F" +|:" 'NR==2{print $4}'
192.168.39.128
[root@centos7 ~]#ifconfig eth0|awk 'NR==2{print $2}'
192.168.39.131
逻辑操作符
&& ;|| ; !
df | awk -F' +|%' '$5>=5 && $5<=15{print $1,$5}' #打印大于5且小于15
/dev/sda2 5
df | awk -F' +|%' '$5>=5 || $5<=10{print $1,$5}' #打印大于5或小于15
Filesystem
Usedevtmpfs 0
tmpfs 0
tmpfs 2
tmpfs 0
/dev/sda2 5
/dev/sda5 1
/dev/sr0 100
df |grep "\/dev\/sd"| awk -F ' +|%' '!($5>=5){print $1,$5}' #打印小于5
/dev/sda1 4
/dev/sda3 1
awk pattern:
#取出非#开头的行
awk '$0 !~ /^#/' /etc/fstab
UUID=49c3f17e-8925-4eae-a1d5-cc1491d5a68e / xfs defaults 0 0
UUID=779239a1-cd4e-4c59-b733-459884443398 /boot xfs defaults 0 0
UUID=0119930b-958b-46c0-af62-99f26fa4bf52 /data xfs defaults 0 0
UUID=64c1b795-7e65-4bda-9111-1469f9f33371 swap swap defaults 0 0
awk '/^UUID/' /etc/fstab
UUID=49c3f17e-8925-4eae-a1d5-cc1491d5a68e / xfs defaults 0 0
UUID=779239a1-cd4e-4c59-b733-459884443398 /boot xfs defaults 0 0
UUID=0119930b-958b-46c0-af62-99f26fa4bf52 /data xfs defaults 0 0
UUID=64c1b795-7e65-4bda-9111-1469f9f33371 swap swap defaults 0 0
awk '!/^UUID/' /etc/fstab
#
# /etc/fstab
# Created by anaconda on Fri Sep 20 15:18:47 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
#打印以root到yu开头的行
awk -F: '/^root/,/^yu/{print $1,$3}' /etc/passwd
#使用awk取出磁盘利用率
df | grep "^\/dev\/sd" |awk -F" +|%" '{print $1 "\t" $5}'
df | grep "^\/dev\/sd" |awk -v FS" +|%" '{print $1 "\t" $5}'
#
#取出远程主机IP地址
ss -nt |grep "^ESTAB" |awk -F" +|:" '{print $6}'
ss -nt|awk -F ' +|:' 'NR!=1{print $6}'
ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}'
#把IP次数超过3次的扔进防火墙
for ip in `ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}' |sort |uniq -c|awk '$1>=3{print $2}'`;do iptables -A INPUT -s $ip -j REJECT;done
ss -nt |awk -F ' +|:' '/^ESTAB/{print $6}' |sort |uniq -c|awk '$1>=3{print $2}'|while read ip;do iptables -A INPUT -s $ip -j REJECT;done
#打印奇数行
seq 10 |awk 'x=!x'
#打印偶数行
seq 10 |awk '!(x=!x)'
seq 10 |awk -v x=1 'x=!x'
awk控制语句
if else
awk取得的整行或字段做条件判断
#判断第三个字段是否大于1000,为真则打印这行的第一列和第三列
awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
#判断最后一列是否等于/bin/bash,为真打印第一列
awk -F: '{if(NF==/bin/bash)print $1}' /etc/passwd
#查找硬盘使用率大小超过80的磁盘
[root@centos7 ~]# df -h|awk -F% '/^\/dev\/sd/{print $1}'
/dev/sda2 100G 4.4G 96G 5
/dev/sda3 50G 33M 50G 1
/dev/sda1 1014M 168M 847M 17
[root@centos7 ~]# df -h|awk -F% '/^\/dev\/sd/{print $1}'|awk '$NF>=80{print $1,$5}'
next 直接处理下一行
exit 退出当前脚本
#next
echo -e "1\n2\n3\n4\n5" >text.txt
awk '{if(NR==2){next}{print $0}}' text.txt
1
3
4
5
#exit
echo -e "1\n2\n3\n4\n5" >text.txt
awk '{if(NR==3){exit}{print $0}}'
1
2
while循环
条件为真进入循环;条件为假退出循环
对一行内多个字段逐一进行处理;对数组中的各元素逐一处理
#显示每个字段的字符个数
awk 'NR==1{print $0 }' /etc/passwd
root:x:0:0:root:/root:/bin/bash
awk -F: '/^root/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/passwd
root 4
x 1
0 1
0 1
root 4
/root 5
/bin/bash 9
#求和1+2+3+...+100
awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++}{print sum}}'
5050
awk -v i=1 -v sum=0'BEGIN{while(i<=100){sum+=i}{print sum}}'
5050
#数字判断大小
awk -F"," '{max=$1;min=$1;i=2;while(i<=NF){if(max<$i){max=$i};if(min>$i){min=$i};i++};print "max="max,"min="min}' test2.txt
#
cat >test<<EOF
1 www.baidu.com
2 www.sina.com
EOF
awk -F'[ .]' '{print $2}' test
baidu
sina
continue
awk 'BEGIN{for(i=1;i<=5;i++){if(i==2){continue}{print i}}}'
1
3
4
5
break
awk 'BEGIN{for(i=1;i<=5;i++){if(i==3){break}{print i}}}'
1
2
awk数组
通过数组的下标,引用数组中的元素,数组下标通常是由0开始,如果引用第一个元素,对应的下标就是【0】,awk可直接为数组中元素赋值
awk 'BEGIN{ huluwa[0]="大娃" ; huluwa[1]="二娃" ;huluwa[2]="三娃";print
huluwa[2] }'
结果为:三娃
awk 'BEGIN{ huluwa[0]="大娃"; huluwa[1]="二娃";huluwa[2]="";print huluwa[2] }'
结果为:空
删除数组
awk 'BEGIN {
huluwa["yiwa"]="大娃"; huluwa["erwa"]="二娃";print
huluwa["yiwa"];delete
huluwa["yiwa"];print huluwa["yiwa"] }'
结果为:大娃
空
#判断连接次数
netstat -tan | awk '/^tcp/{ip[$NF]++}END{for(i in ip) { print i,ip[i]}}'#以$NF为变量做循环,打印变量,和出现次数,++表示每出现相同ip就加1