awk的介绍和使用

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

你可能感兴趣的:(awk的介绍和使用)