[TOC]
awk介绍 awk是Linux三剑客中功能最强大,使用最复杂的命令。强大到awk都成为一种语言了,它适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了 awk将会使你的工作变的高大上。 awk 是三剑客的老大,利剑出鞘,必会不同凡响。
awk基本用法 输入awk就可以看到awk简要帮助,下面就结合我自己查找资料和使用之后的一个总结:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 awk基本用法 awk [options] 'program' var=value file… awk [options] -f programfile var=value file… 'program' = 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' options(选项): -f progfile --file=progfile #从文件中读取program语法 -F fs --field-separator=fs #字段分隔符,默认空格 -v var=val --assign=var=val #自定义变量 #官方简单例子,将/etc/passwd以冒号":"分隔,将得到的的第一列打印 #gawk -F: '{ print $1 }' /etc/passwd root bin daemon ...
1.分隔符.域和记录 awk执行时,参数-F
的值就是分隔符,不写默认为空格.
分割出来的字段就是域,从前往后一次标记为$1,$2,$3...$n
称为域标示.$0
为所有域.
文件的每一行称为一条记录.
2.awk语法 1 2 3 4 5 6 program: 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' pattern和action: pattern部分决定动作语句何时触发及触发事件(BEGIN,END 也是属于pattern中的特殊部分吧) action statements对数据进行处理,放在{}内指明 (print, printf)
3.awk工作过程 awk的工作过程: 第一步: 执行 BEGAIN{action;…} 语句块中的语句,如果没有就跳过此步骤. 第二步: 从文件和标准输入读取一行(就是一条记录),然后按照pattern中匹配中了就执行后面的 { action;… } ,然后读取下一条记录匹配执行,重复这个过程知道文件全部读取完毕. 第三步: 执行 END{ action;… } 语句块中的语句,如果没有就跳过此步骤.
注意:
pattern是可选的,省略action,则默认执行print $0 的操作.但是呢,pattern和{ action;} 不能同时省略.
1 2 3 4 5 6 7 8 9 10 11 12 13 [yhu@master model]$awk /root/{print} /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [yhu@master model]$awk /root/ /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [yhu@master model]$awk {print} /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 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin ...
4.print格式 print格式:print item1, item2, … 要点:
(1) 逗号分隔符 (2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式,输出的各项item 以空格隔开(默认) (3) 如省略item,相当于print $0 示例:
1 2 3 4 awk –F: ‘{print $1}’ /etc/passwd #冒号分割,每一条记录打印第一个域 awk –F: ‘{print $0}’ /etc/passwd #冒号分割,每一条记录打印全部域 awk –F: ‘{print $1”\t”$3}’ /etc/passwd #冒号分割,每一条记录打印第一个域一个制表符再打印第三个域 tail –3 /etc/fstab|awk ‘{print $2,$4}’ #传入/etc/fstab后三行,空格分割,每一条记录打印第二个域和第四个域
5.awk变量 变量分为内置变量和自定义变量.
内置变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 FS:输入字段分隔符,默认为空白字符 filed separator awk -v FS=':' '{print $1,$3,$7}' /etc/passwd awk –F: '{print $1,$3,$7}' /etc/passwd OFS:输出字段分隔符,默认为空白字符 output filed separator awk -v FS=':' -v OFS='-' '{print $1,$3,$7}' /etc/passwd RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效 record separator awk -v RS=' ' '{print }' /etc/passwd ORS:输出记录分隔符,输出时用指定符号代替换行符 output record separator awk -v RS=' ' -v ORS='###' '{print }' /etc/passwd NF:字段数量 number filed awk -F: '{print NF}' /etc/passwd ,引用内置变量不用$ awk -F: '{print $(NF-1)}' /etc/passwd NR:行号 number row awk '{print NR}' /etc/fstab; awk END'{print NR}' /etc/fstab awk 'BEGIN{print 0} {print NR} END{print NR}' /etc/fstab FNR:各文件分别计数,行号 file number row awk '{print FNR}' /etc/fstab /etc/inittab FILENAME:当前文件名 awk '{print FILENAME}' /etc/fstab ARGC:命令行参数的个数 arguement count awk '{print ARGC}' /etc/fstab /etc/inittab awk 'BEGIN{print ARGC}' /etc/fstab /etc/inittab ARGV:数组,保存的是命令行所给定的各参数 arguement value awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/ --> awk awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab --> /etc/fstab 自定义变量(区分字符大小写) (1) -v var=value (2) 在program中直接定义 示例: awk -v test='hello gawk' '{print test}' /etc/fstab awk -v test='hello gawk' 'BEGIN{print test}' awk 'BEGIN{test="hello,gawk";printtest}' awk –F:‘{sex=“male”;print$1,sex,age;age=18}’ /etc/passwd cat awkscript {print script,$1,$2} awk -F: -f awkscriptscript=“awk” /etc/passwd
自定义变量 自定义变量可以在两个地方定义:
1 2 (1) -v var=value (2) 在program中直接定义
示例:
1 2 3 4 5 6 7 awk -v test='hello gawk' '{print test}' /etc/fstab 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
6.printf printf : 格式化输出,输出各种你想要的格式.(ascii,十进制整数,十六进制,无符号,小数…)
格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 printf “FORMAT”, item1, item2, ... FORMAT格式符:与item一一对应 %c: 显示字符的ASCII码 %d, %i: 显示十进制整数 %e, %E:显示科学计数法数值 %f:显示为浮点数 %g, %G:以科学计数法或浮点形式显示数值 %s:显示字符串 %u:无符号整数 %%: 显示%自身 FORMAT修饰符: #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f -: 左对齐(默认右对齐)%-15s +:显示数值的正负符号%+d
注意:
1 2 3 4 (1) 必须指定FORMAT,记得加引号 (2) 不会自动换行,需要显式给出换行控制符,\n (3) FORMAT中需要分别为后面每个item指定格式符 (4) 是printf哦,不是print
示例:
1 2 3 4 5 6 7 awk -F: '{printf "%s",$1}' /etc/passwd awk -F: '{printf "%s\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: %s,UID:%d\n",$1,$3}' /etc/passwd awk -F: '{printf "Username: %15s,UID:%d\n",$1,$3}' /etc/passwd awk -F: '{printf "Username: %-25sUID: %d\n",$1,$3}' /etc/passwd
7.操作符 awk操作符就多了,有算数操作符,字符串操作符,赋值操作符,比较操作符,模式匹配符,逻辑操作符.是不是在学一门语言啊?O(∩_∩)O哈哈~ 其实每一个都很简单,就一般程序操作符基本一样.来看下
算数操作符 1 2 3 x+y, x-y, x*y, x/y, x^y, x%y -x: 转换为负数 +x: 转换为数值
字符串操作符 在没有符号的操作符,字符串就连接起来了.
赋值操作符 1 2 =, +=, -=, *=, /=, %=, ^= ++, --
模式匹配符 1 2 3 4 5 6 ~:左边是否和右边匹配包含 !~:是否不匹配 awk -F: '$0 ~ /root/{print $1}' /etc/passwd awk '$0~"^root"' /etc/passwd awk '$0 !~ /root/' /etc/passwd awk -F: '$3==0' /etc/passwd
逻辑操作符 1 2 3 4 5 6 7 8 与&& 或|| 非! 示例: awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd awk -F: '!($3==0){print $1}' /etc/passwd awk -F: '!($3>=500) {print $3}' /etc/passwd
函数调用 1 function_name(argu1, argu2, ...)
条件表达式 1 selector?if-true-expression:if-false-expression
示例:
1 2 3 4 5 awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%20s: %-s\n",$1,usertype}' /etc/passwd # selector --> ($3>=1000) # if-true-expression --> (usertype="Common User") # if-false-expression --> (usertype="Sysadmin or SysUser")
8.awk pattern pattern:根据pattern条件,过滤匹配的行,在做处理
(1)如果未指定:空模式,匹配每一行 (2) /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
1 2 awk '/^UUID/{print $1}' /etc/fstab awk '!/^UUID/{print $1}' /etc/fstab
(3) relational expression: 关系表达式,结果为“真”才会被处理
1 2 3 4 5 6 7 8 真:结果为非0值,非空字符串 假:结果为空字符串或0值 awk -F: 'i=1;j=1{print i,j}' /etc/passwd awk '!0' /etc/passwd; awk '!1' /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 awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
(4) line ranges:行范围
startline,endline:/pat1/,/pat2/不支持直接给出数字格式
1 2 awk -F: '/^root\>/,/^nobody\>/{print $1}' /etc/passwd awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
(5) BEGIN/END模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
示例:
1 2 3 4 5 6 7 8 9 10 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--------------------------"} {printf "%-20s%s\n" ,$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'
9.awk action 常用的action分类 (1) Expressions:算术,比较表达式等 (2) Control statements:if, while等 (3) Compound statements:组合语句 (4) input statements (5) output statements:print等
控制语句 action中的控制语句是强大的,现在挑几个重要且常用说:
1 2 3 4 5 6 7 8 9 10 11 { statements;… } 组合语句 if(condition) {statements;…} if(condition) {statements;…} else {statements;…} while(conditon) {statments;…} do {statements;…} while(condition) for(expr1;expr2;expr3) {statements;…} break continue delete array[index] delete array exit
if-else 语法:
1 2 3 if(condition){statement;…}[else {statement;…}] if(condition1){statement1}else if(condition2){statement2} else{statement3}
使用场景:对awk取得的整行或某个字段做条件判断 示例:
1 2 3 4 5 6 7 8 9 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/{print $1}'|awk '$NF>=80{print $1,$5}‘ awk 'BEGIN{ test=100;if(test>90){print "very good"} else if(test>60){ print "good"}else{print "no pass"}}'
while 语法:while(condition){statement;…}
条件“真”,进入循环;条件“假”,退出循环 使用场景: 对一行内的多个字段逐一类似处理时使用 对数组中的各元素逐一处理时使用 示例:
1 2 awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i); i++}}' /etc/grub2.cfg awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10) {print $i,length($i)}; i++}}' /etc/grub2.cfg
do-while 语法:do {statement;…} while(condition)
意义:无论真假,至少执行一次循环体 示例:
1 awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
for 语法:for(expr1;expr2;expr3) {statement;…}
特殊用法:能够遍历数组中的元素; 语法:for(varin array) {for-body}
1 2 3 4 5 6 awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg 性能比较: 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)
switch 语法:
1 switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;...; default: statementn}
break和continue 1 2 awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}' awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
函数 数值处理:rand()
:返回0和1之间一个随机数
1 awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
字符串处理:length([s])
:返回指定字符串的长度sub(r,s,[t])
:对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
1 echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)'
gsub(r,s,[t])
:对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
1 echo "2008:08:08 08:08:08" | awk 'gsub(/:/,“-",$0)'
split(s,array,[r])
:以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
1 netstat-tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (iin count) {print i,count[i]}}'
自定义函数 格式:
1 2 3 4 function name ( parameter, parameter, ... ) { statements return expression }
示例:
1 2 3 4 5 6 7 #cat fun.awk function max(v1,v2) { v1>v2?var=v1:var=v2 return var } BEGIN{a=3;b=2;print max(a,b)} #awk –f fun.awk
调用shell命令 system命令
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用””引用起来。
1 2 awk BEGIN'{system("hostname") }' awk 'BEGIN{score=100; system("echo your score is " score) }'
10.调用脚本 将awk程序写成脚本,直接调用或执行
示例:
1 2 3 4 5 6 7 8 9 10 11 12 #cat f1.awk if($3>=1000)print $1,$3} #awk -F: -f f1.awk /etc/passwd #cat f2.awk #!/bin/awk –f #this is a awk script {if($3>=1000)print $1,$3} #chmod +x f2.awk #f2.awk –F: /etc/passwd
测试:
1 2 3 4 1、统计/etc/fstab文件中每个文件系统类型出现的次数 2、统计/etc/fstab文件中每个单词出现的次数 3、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字 4、解决DOS攻击生产案例:根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100,即调用防火墙命令封掉对应的IP,监控频率每隔5分钟。防火墙命令为:iptables -A INPUT -s IP -j REJECT