awk


流编辑器sed,用于对行进行删除,替换等操作,awk更适合用来排版。


awk工作流程


  awk将文本的内容逐行读取到内存中,awk会对读取进内存的行通过某种分隔符(默认为空格\t)进行分块,分块后会对各个块命名
$0-整个行,$1-第一个块,$2-第二个块...$n-第n个块.此时可以指定awk操作的块.同sed一样,awk会通过模式匹配需要操作的
行,不同的是对于未匹配的行,awk会将其忽略。


#ifconfig eth0 | awk '/inet addr/{print $2}' | awk -F: '{print $2}'


注*
1.awk通过模式/inet addr/匹配特有的行,然后再默认分割符分块的情况下打印第二块.
2.通过指定分割符:将内容分为俩段,打印第二块。


awk的语法


awk [-F] '/模式/{命令}'  file
1.通过模式匹配需要操作的行,未匹配到的行忽略.
2.awk常用于排版,常用的命令为print
3.分割符可加参数F指定


awk中的变量-NF,NR,FNR
1.NF:对读取进内存的行的分块数.
#ifconfig eth0 | awk '/inet addr/{print NF}'
->4


注:在awk中,引用变量不需要加$(除了引用块$n),$NF代表$4
#ifconfig eth0 |awk '/inet addr/{print $NF}'
->mask:255.255.255.0   ----打印第四块


2.NR,FNR
1.对于同一文件而言,NR和FNR代表的都是读取当前操作的行.
2.对于同时操作2个文件时,NR代表读取当前操作的行,而FNR读取的是每个文件操作的当前的行.


demo:存在俩个文件file1,file2.其中file1中有4行,file2中有2行。


#awk '{print NR}' file1 file2
1
2
3
4
5
6
#awk '{print FNR}' file1 file2
1
2
3
4
1
2


注:当对多个文件操作时,判断是对哪个文件进行操作,比较NR和FNR的值即可.


在{}执行多条命令时,需要用;号隔开
#ifconfig eth0 | awk '{print NR,$2;print NR}'                   -------默认有换行符


在awk中做比较
1.数字比较用到的运算符:==,>=,>,<,<=
2.表示字符串能否匹配上的符号:~


注:比较时,在模式位置数字不必用//环绕,字符串需要用//环绕起来.


#awk -F: '$3>=500{print $1}'  /etc/passwd


->打印/etc/passwd中uid>500的普通用户的用户名


#awk -F:  '/^root/{print $1}' /etc/passwd


->打印/etc/passwd中以root开头的行.


可用&&和||运算符连接多个条件.
#awk -F: '$3==0||$3>=500{print $1}' /etc/passwd


->打印/etc/passwd中的root用户和普通用户.


对于字符串的比较则是判断字符串能否匹配上
#awk -F: '/root/{print }' /etc/passwd
#awk -F: '$5 ~/root/{print }' /etc/passwd


->第一个语句是在文件中搜寻包含root的行打印出来,而第二句则是在文件中按:分割开来,匹配第5部分的root后打印出来.



awk在对文本处理之前可做某些操作,这些操作在BEGIN{}中定义,当awk对文本处理完毕之后可做一些扫尾工作,在END{}中定义.
1.在BEGIN{}中可定义标题及一些变量.
2.定义分割符FS


awk 'BEGIN{命令1;命令2...}/模式/{命令m;命令n}END{命令x;命令y}' file
#awl  'BEGIN{FS=':' $5~/root/{print}' /etc/passwd
#awk 'BEGIN{FS=':' print "用户名"}$3>=500||$3==0{print $1}END{print "end"}' /etc/passwd



awk作为和bash一个软件级别,其本身也是一门编程语言,支持高级语言的特性.


1.awk和read读取文件中的行,read只读取一行,读完文本需要利用for循环,awk本身自带循环.
2.awk支持高级编程语言的流程控制,循环语句,函数等功能.


awk支持流程控制if


if语句语法
if(判断){语句1}else if(判断2){语句2}else{语句3}


注:流程控制和循环都需要写入{}中


用if语句实现列出/etc/passwd中不同用户.


awk -F: '{if($3==0{print "root usr"} else if($3>=500){print "common usr"} else{print "sys usr"}}' /etc/passwd


三目运算符
#awk -F: '{print($==0?"root":"not root")}' /etc/passwd



awk支持循环语句for-while


while语句语法


while(条件){
语句1
语句2
...
}


demo:将/etc/passwd中root用户行按分隔符分开部分分成不同的行来写.


root:x:0:0:xxxxx:/root/:/bin/bash


root
x
0
0
xxxxx
/root/
/bin/bash



awk -F: '$1~/root/{
print "---------------------------------"
i=1
while(i<=NF){print $i ;i++}
}' /etc/passwd


当满足某个条件时跳出循环-break


awk -F: '{
print "---------------------------------"
i=1
while(i<=NF{
if($1~/shutdown/){break}
print $i,i++}
}' /etc/passwd


当遇到next时下面的语句不再执行-next



for循环语法结构


for(i=1;i<n;i++){
语句
}


awk -F: '{print "----------------------------"
for(i=1;i<=NF;i++){print $i}
}' /etc/passwd


demo:系统内存管理是通过分配页面管理的,对于未写入硬盘的为脏页,反之为干净页.


统计某个进程占用多少脏页,多少干净页


cat /proc/1/smaps | awk '/Shard_Clean/{AA +=$2}' /Shard_Dirty/{BB +=$2}END{print "clean page:"AA"kb" ;print "dirty pages:"BB"kb" }



awk支持数组,数组定义连续的值,值为元素


1.在awk中,数组的下标不一定非得是数字,所以称散列更合适.
2.在awk中,数组的下标定义为字符串是要用""引起来


定义数组和引用数组
echo '' | awk '{aa[1]=111 aa[2]=222 print aa[1]}'
echo '' | awk '{aa["a"]=111 aa["b"]=222 print aa["a"]}'


demo:统计俩个文件中相关联的项目(如统计一个人用×××办的不同银行卡)


#cat aa
tom:001
bob:002


#cat bb
001:aa
001:bb
002:cc
002:dd


结果集要求
tom:001:aa
tom:001:bb


bob:002:cc
bob:002:dd


现对aa操作用a数组a文件中的值定义数组
aa["$2"]=$0


->可实现
aa[001]=tom:001
aa[002]=bob:002


对bb操作
->此时aa中的$2和bb中的$1是相同的值,引用数组正常
aa[001]=tom:001
aa[002]=bob:002


awk -F: 'NR==FNR{aa[$2]=$0;next}{print aa[$1":"$2]}' aa bb



awk中常用的函数-sub/gsub-length-subsrt


#awk '{sub("tom","TOM");print $0}' file
#awk '{gsub("tom","TOM");print $0}' file


demo:系统监控时,利用gnuplot,rrdtool工具需将时间转化为秒数
#LANG=C sar 1 > aa.sar
#date -d '12:21:11' +%s


length()                           计算字符串长度
substr('字符串',m,n)           从m位置开始截取n个字符串



注* printf 格式化输出


#awk -F '/root/{printf "%s        %s\n",$1,$5}' /etc/passwd
#awk -F '/root/{printf "20%s          %20s\n"}' /etc/passwd