GUN awk
文本处理三工具:grup,sed,awk
grep,egrep,fgrep:文本过滤工具
sed:行编辑器
模式空间,保持空间
awk:报告生成器,格式化文本输出工具
AWK:(Aho, Weinberger, Kernighan) 报告生成器,格式化文本输出
有多种版本: New awk( nawk), GNU awk(gawk).linux使用gawk
/usr/bin/awk是gawk的链接文件,所以gawk也可以叫做awk
name:gawk – 模式扫描和处理语言
awk其实是一门编程语言的解释器,本身也可以说是一门语言,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部分组成
program:通常是被单引号或双引号中
program:PATTERN{ACTION STATRMENTS}:模式{动作语句1;的语句2;.....}
花括号中多语句之间用分号分隔
此处的模式跟sed中的模式不一样,有地址定界的含义,动作语句无非是让一个指令对某些数据处理,并额外在指实现些过程式编程语言关键字完成某些动作的执行结果的控制,动作语言引用的是awk内置的支持命令,例print,printf(格式化输出)
options:
-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量
处理文本机制:
从指定的文件中,一次读取一行文本;把读取的整行文本用事先指定的输入分隔符切片,分成N个组成部分,分隔符默认为空白,把每一片自动保存在awk自建的变量中.内建变量叫做$1,$2....,文本片有多少,会建立与之相对数量的位置变量.格式化输出,就是在文本切割成片以后,让我们仅显示诸多片段中的某一段,某些段,全部段($0).
还可以对每个片段进行额外的加工处理;
还可以对切割出的片段,进行条件过滤,例,每行文本中的第二片,是否在一个数值范围内,在的话,就把这行当中的第四段显示出来;
还可以对每行文本的每个字段做循环,对字段做单独处理;注意:AWK的循环功能不是在行间循环,Awk本身可以遍历文件,有循环功能;这里指的循环是在字段间完成遍历操作.因为一行有N个字段,要逐字段进行处理的话,就必须要用到循环机制来完成
常用输出命令
1.print
print item1,item2...
要点:
(1)逗号分隔item
(2)输出的各item可以字符串,数值,当前记录的字段,变量或awk的表达式;
(3)如省略item,相当于print $0
awk '{print}'
awk '{print ""}' 打印空白
2.变量
2.1内建变量:
FS: input field seperator 指定输入字段分隔符
OFs:output field seperator指定输出字段分隔符
RS:input record seperator指定输入时的换行符
ORS:input record seperator指定输出时的换行符
NF:number of field 字段数量
注意:NF不加$,在awk内部引用变量无须加$;$NF不是引用变量,而是显示字段;
NR:number of record 文件行数
FNR:各文件计数,文件行数
FILENAME:当前文件名
ARGC:命令行中的参数个数
ARGV:内建数组,保存的是命令行所给定的各参数;









2.2自定义变量: (1)-v var=value 变量名区分字符大小写 (2)在program中直接定义

3.printf命令 格式化输出:printf "FORMAT",item1,item2..... 每一项对位放在FORMAT中进行显示 ,FPRMAT是格式符,会为每一个item占位,留一个特定格式符号占在那里,item会显示在FORMAT所指定的对应的格式符号的位置上.而不是写一个item,就放在那里显示,这就是格式化输出机制. (1)FORMAT必须给出 (2)不会自动换行,需要显式给出换行控制符,\n (3)FORMAT中需要分别为后面的每个item指定一个格式化符号; 格式符: %c:显示字符的ASCII码 %d,%i:显示十进制整数 %e,%E:科学技术法数值显示 %f:显示为浮点数 %g,%G:以科学计数法或浮点形式显示数值 %s:显示字符串 %u:无符号整数 %%显示%本身


修饰符:每一个格式符都有其修饰符,可以在格式符前面加修饰的符号,用来控制这种格式显示机制 #[.#]:第一个数字控制显示的宽度:第二个#显示小数点后的精度(不是小数可省略): 例: %3.1f %15s -:左对齐 +显示数值的符号


4.操作符:
算术操作符:
x+y x-y x*y x/y x%y x^y
-x:赋值,把正数转换为负数
+x:转换为数值
字符操作符: 没有符号的操作符,字符串连接
赋值操作符:
= += -= *= /= %= ^=
++ --
比较操作符:
> >= < <= != ==
模式匹配符:
~:左边是否被右侧匹配包含
!~:是否不匹配
cat /etc/passwd |awk '$0 ~ /root/'|wc -l
cat /etc/passwd |awk '$0 !~ /root/'|wc -l
逻辑操作符:
&&:与
||:或
!:非
函数调用:
function_name(argu1,argu2,...)
条件表达式:
selector?if-true-expression:if-false-expression
示例:
awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
5 PATTERN:根据pattern条件,过滤匹配的行,再做处理
(1)empty:空模式,匹配每一行
(2)/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
awk '/^UUID/{print $1}' /etc/fstab
awk '!/^UUID/{print $1}' /etc/fstab
(3)relational expression: 关系表达式;结果有“真”有“假”;结果为“真”才会被处理;
真:结果为非0值,非空字符串
假:结果为空字符串
示例:
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
seq 10 | awk 'i=!i
(4) line ranges: 行范围
startline,endline: /pat1/,/pat2/ 不支持直接给出数字格式
awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd
awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
(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 "==============\n END "}' /etc/passwd
6.常用的action
(1)Expressions
(2)control statements:if while等
(3)Compound statements:组合语句:
(4)input statements
(5)output statememts
7.控制语句
if(condition){statments}
if(condition){statments} else {statements}
while(condition){statments}
do{statments} while(condition)
for(expr1;expr2;expr3){statments}
break
continue
next
delete array[index]
delete array
exit
{ statements }
(1)if-else
使用场景:对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/{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"}}'




(2)while循环 语法:while(condition) statement 条件为真,进入循环,条件为假,退出循环 使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的个元素逐一处理时使用


(3)do-while循环
语法:do{statments} while(condition)
先执行一遍循环体,在进行判断,是否继续执行,至少执行一次循环体
思考:下面两语句有何不同?
awk ‘BEGIN{i=0;print ++i,i}’
awk ‘BEGIN{i=0;print i++,i}’


(4)for循环
语法:for (expr1;expr2;expr3) statement
for(variable assignment;condittion;iteration process) {statement(for-body)}
特殊用法:能够遍历数组中的元素;
语法:for(var in array) {for-body}
示例:
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};dototal=$(($total+i));done;echo $total)
time(for ((i=0;i<=10000;i++));do let total+=i;done;echo$total)

(5)switch语句(相当于shell的case语句;多重if条件判断)
使用场景:多用于字符串比较判断
语法:switch(expression) {case VALUE1 or /REGEXP; statement;case VALUE2 or /REGEXP; statement;...;default:statement}
switch 跟上表达式,判断符合哪个case,case是关键字,value是值,REGEXP是正则表达式,如果表达式的值等于value的值或者能被REGEXP所匹配,就执行第一个分支statement;否则跟第二个case向匹配,一直向下,知道匹配成功,最后有默认分支default.
(6)break和continue
break[n]:跳出N层循环
continue:提前结束本层循环,进入下一轮循环

(7)next 控制awk的内生循环功能 提前结束对本行的处理而直接进入下一行

awk的数组(array) 连续的内存空间,有索引 数字索引数组 自定义索引数组,称关联数组,在awk中使用最多 array[index-expression] index-expression: (1)可使用任意字符串,字符串要使用双引号; (2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串" 若要判断数组中是否存在某元素,要使用"index in array"格式进行 若要遍历数组中的每个元素,要使用for循环,注意:var变量会遍历数组的每个索引,索引次序不会按常规逻辑,除非要人为排序.

如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串",如果把初始值当做数值,就是当做0来用.如果某个元素不存在,创建后++,就把数值累加;这种使用场景在统计某个字段或数值出现次数时特别有用

统计netstat中的状态出现次数,用awk取得最后一字段,把最后一字段当做数组的索引,数组随便取名,例如"state["LISTEN"],每读取一行就试图把最后一字段当做索引下标,来对对应的数组元素实行自增操作, 因此索引对应的数组元素是最后字段的出现次数


练习1:统计/etc/fstab文件中每个单词中出现的次数

练习2:统计/etc/fstab文件中每个文件系统类型出现的次数

awk函数
内置函数
数值处理:
rand() :返回0和1之件的一个随机数
例:awk 'BEGIN{print rand()}' 注意:在第一个awk命令中生成随机数,相同命令的数值使用第一词生成的随机数,可修改


字符串处理: length([s]):返回指定字符串的长度 sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s多代表的内容,命令结果为命令执行状态,不输出命令结果

gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现的均替换为s多代表的内容;

split(s,a,[r]):以r为分隔符,切割字符s,并将切割后的结果保存至a所表示的数组当中,第一个索引值为1 ,第二个索引值为2...

自定义函数
参考文献:<<sed和AWK>>
格式:
function name ( parameter(变量名), parameter, ... ) {
statements
return expression
}
示例:
#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


awk中调用shell命令
system参数
空格是awk中的字符串连接符,如果system中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用""引用起来。
示例:
awk BEGIN'{system("hostname") }'
awk 'BEGIN{score=100; system("echo your scoreis " score)}'

awk脚本
将awk程序写成脚本,直接调用或执行
示例:
#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
向awk脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
示例:
#cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}
#chmod +x test.awk
#test.awk -F: min=100 max=200 /etc/passwd
实战:
1、 统计/etc/fstab文件中每个文件系统类型出现的次数
# awk '/^UUID/{fs[$3]++}END{for(i in fs) {printi,fs[i]}}' /etc/fstab
2、 统计/etc/fstab文件中每个单词出现的次数;
# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i incount) {print i,count[i]}}' /etc/fstab
原创文章,作者:wencx,如若转载,请注明出处:http://www.178linux.com/48211

