1 awk的介绍
awk: Aho,Weinberger,Kernighan,报告生成器.格式化输出
grep: 文本过滤 egrep pattern
sed: 行编辑器 模式空间 保持空间
基本用法
gawk [ POSIX or GNU style options ] -f program-file [ -- ] file ...
gawk [ POSIX or GNU style options ] [ -- ] program-text file ...
awk 程序通常使用:BEGIN语句块,能使用模式空间匹配的通用块,END语句块,共三部分组成
program 通常使用单引号
基本格式:awk [options] 'program' file…
program:pattern{action statements;..}
pattern 和action: :
pattern 部分决定动作语句何时触发及触发事件
BEGIN,END
action statements 对数据进行处理,放在{} 内指明
print, printf
分割符、域和记录
awk 执行时, 由 分隔符分隔的字段(域)标记$1,$2..$n称 称为域标识。$0 为所有域,注意:和shell 中变量$ 符含义不同
文件的每一行称为记录
省略action行 ,则默认执行 print $0 的 的 操作
print格式: print item1,item2 ...
要点:
1 逗号分隔
2 输出的各item可以字符串,也可以是数值,当前记录的字段,变量或awk的表达式
3 如果省略item 相当于print $0
示例:
1 awk '{print "hello"}'
[root@test5(172.18.254.5) ~]#awk '{print "hello,world,awk" }'
a
hello,world,awk
b
hello,world,awk
2 awk -F: '{print $0}' /etc/passwd
[root@test5(172.18.254.5) ~]#awk -F: -v ORS=' ' '{print $1}' /etc/passwd
root bin daemon adm lp sync shutdown halt mail uucp operator games gopher ftp nobody dbus vcsa abrt haldaemon ntp sasl
auth postfix sshd tcpdump
# 指明输出使用的记录分隔符
2 awk 的变量 需要使用 -v 指定
FS: 输入字段分隔符,默认为空白字符
OFS: 输出字段分隔符,默认为空白字符
RS: 输入记录分隔符,指定输入时的换行符,原换行符仍有效
ORS: 输出记录分隔符,输出时用指定符号代替换行符
NF: 字段数量
NR: 行号,如果是多个文件,将一起计数
FNR: 行号,如果是多个文件,将分别计数
FILENAME: 当前参数文件名
ARGV: 命令行参数的个数
ARGV:数组,保存的是命令行所指定的各参数
[root@test5(172.18.254.5) ~]#awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2]}' /etc/passwd /etc/issue
awk /etc/passwd /etc/issue
# 用户自定义的变量
awk –F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
printf命令 当使用printf的时候 print的变量有时候不起作用
格式化输出:printf “FORMAT ”, item1, item2, ...
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT 中需要分别为后面每个item 指定格式符
格式符:与item 一一对应
%c: 显示字符的ASCII码 码
%d, %i: 显示十进制整数
%e, %E: 显示科学计数法数值
%f :显示为浮点数
%g, %G :以科学计数法或浮点形式显示数值
%s :显示字符串
%u :无符号整数
%%: 显示% 自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个# 表示小数点后精度,%3.1f
-: 左对齐(默认右对齐) %-15s
+: 显示数值的正负符号 %+d
将数字对应的ascii打印出来
[root@test5(172.18.254.5) ~]#cat test.txt
88 89 90
[root@test5(172.18.254.5) ~]#awk '{i=1;while(i<=NF){printf "%c\n",$i;i++}}' test.txt
X
Y
Z
将ascii对应的数字打印出来
[root@test5(172.18.254.5) ~]#for i in {a..z};do printf "%d " "'$i";done
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
获取磁盘利用率
df -P | awk -F"[% ]" '/\/dev/&& $(NF-2) >= 10{print $1,$(NF-2)}'
awk的一些定义
awk 'BEGIN{i=0;print i++,i}' 1 1 i=i++
awk 'BEGIN{i=0;print ++i,i}' 0 1 i=++i
awk '{i=1;sum=0;while(i<=NF){sum+=$i;i++};print sum,i}' /file.txt
# 可以将 每行计算一个数字
awk '{i=1;while(i<=NF){sum+=$i;i++};print sum,i}' /file.txt
# 可以将 每行中的数加在一起 统计出来一个数字
pattern 类似 sed 的定界符
1 empty:空模式 匹配任一行
2 /regular expression/:仅处理被pattern匹配到的行
3 relational expression :关系表达式 结果 有真 有假 结果为真 才会被处理 假 过滤
真 结果为非零 非空串;
awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
awk -F: '$NF="/bin/bash"{print $1,$NF}' /etc/passwd
4 line range 行范围
tartline endline /pat1/,/pat2/
awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
5 BEGIN/END 模式
BEGIN():仅在开始处理文件中的文本之前执行一次 在未执行pattern中执行之前,执行END() 仅在文本处理完成之后执行一次
awk -F: 'BEGIN{print " USERNAME uid \n"}{printf "%-20s%3s\n",$1,$3}END{print "***************************\n end"}' /etc/passwd
3 控制语句
if (condition) {statements}
if (condition) {statements} else {statements}
do {statements} while(condition)
for (expr;expr2;expr3){statements}
break
continue
delete array[index]
delete array
exit
{ statements }
1 if-else
语法 if(condition) statement [else statement]
awk -F: '{if($NF~/bash$/) print $1,$NF}' /etc/passwd
awk -F: '{if($3>1000) {printf "common user:%s\n",$1} else {printf "root or sysuser:%s\n",$1}}' /etc/passwd
awk '{if(NF>7) print $0}' /etc/fstab
df -hP | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>30) print $1}'
使用场景:对awk取得的整行或某个字段做条件判断
2 while
语法 while (condition) statement
条件为真 进入循环 条件为假 退出循环
使用场景 对一行内的多个字段逐一做类似处理时使用,对数组中的各元素逐一处理使用
awk '/^[[:space:]]+linux16/{i=1;while(i=7) print $i,length($i);i++}}' /etc/grub2.cfg
3 do..while
语法 do statement while(condition)
意义 至少运行一次
4 for 循环
语法 for(expr1;expr2;expr3) statement
特殊用法
能够遍历数组中的元素
语法 for(var in array){for body}
5 switch 语句
语法:switch(expression) {case value or /pat/: statement;case value2 or /pat2/: statement;...default:statement}
6 break和continue
break [n] 退出几层循环
continue 退出当前循环
7 next 控制awk 的内生循环
提前结束对本行的处理而直接进入下一行
awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd
4 数组
关联数组 array[index-expression]
index-expression
1 可使用任意字符串 字符串要是用双引号
2 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其初始化为空串要判断数组中是否存在某元素,要是用index in array 格式进行
去除重复的行
awk -F":" '!a[$7]++' /etc/passwd
显示行重复的次数
awk -F":" '{!a[$0]++;print $0,a[$0]}' test.txt
若要遍历数组中的每一个元素,要是用for 循环
for(var in array) statement
awk 'BEGIN{weekends["mon"]="Monday";weekends["tue"]="Tuesday";for(i in weekends){print weekends[i]}}'
注意 var 会遍历array 的每一个索引
netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}'
练习
统计/etc/fstab 文件中每个单词出现的次数
awk '{i=1;while(i<=NF){danci[$i]++;i++}}END{for(i in danci){print i,danci[i]}}' /etc/fstab
统计/etc/fstab文件中 文件系统的类型及个数
awk '/^\/dev|^UUID/{type[$3]++}END{for(i in type){print i,type[i]}}' /etc/fstab
5 内置函数
数值处理
rand();返回0和1之间的随机数 只有第一次使用时随机的,(不做特殊处理)以后都会相同的
需要生成一个种子 srand()
awk 'BEGIN{srand();for(i=1;i<=10;i++)printf "%d ",rand()*100}'
awk 'BEGIN{srand();print rand()}'
awk 'BEGIN{srand();printf "%d",rand()*100 }'
awk 'BEGIN{srand();print int(rand()*100) }'
字符串处理
length([s]) 返回字符串长度
sub(r,s[t])以r表示的模式来查找t所代表的字符串中的匹配的内容,并将其第一次出现替换为s所代表的内容
echo "2008:08:08 08:08:08" |awk 'sub(/:/,"-",$1)'
2008-08:08
gsub(r,s[t])以r表示的模式来查找t所代表的字符串中的匹配的内容,并 将所有出现均替换为s所代表的内容
echo "2008:08:08 08:08:08" |awk 'gsub(/:/,"-",$1)'
2008-08:08
split(s,a[,r]):以r为分隔符切割s字符,并将切割后的结果保存至a所表示的数组当中下标从1开始
netstat -tan | awk '/^tcp\>/{split($5,ip,":");print ip[1]}'
netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
练习
1 、统计/etc/fstab 文件中每个文件系统类型出现的次数
awk '!/^#/&&!/^$/{type[$3]++}END{for(i in type){print i,type[i]}}' /etc/fstab
awk '/^[^#]/{type[$3]++}END{for(i in type){print i,type[i]}}' /etc/fstab
2 、统计/etc/fstab 文件中每个单词出现的次数
awk '{i=1;while(i<=NF){danci[$i]++;i++}}END{for(i in danci){print i,danci[i]}}' /etc/fstab
3 、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中 中的所有数字
echo 'Yd$C@M05MB%9&Bdh7dq+YVixp3vpw' | awk -v FS="[^0-9]+" '{i=1;while(i<=NF){{if($i ~ "[0-9]+")print $i};i++}}'
4 、解决DOS 攻击生产案例:根据web 日志或者或者网络连接数,监控当某个IP 并发连接数或者短时内PV 达到100 ,即调用防火墙命令封掉对应的IP ,监控频率每隔5 分钟。防火墙命令为:iptables -A INPUT -s IP -j REJECT
#!/bash
declare -a dos
while :;do
dos=(`awk '{ip[$1]++}END{for(i in ip){if(ip[i]>100)print i}}' test.txt`)
for i in ${dos[@]};do
iptables -A INPUT -s $i -j REJECT
done
sleep 300
done