1、awk格式
awk 选项 '命令体' file1,file2...
选项:-F 指定分隔符,默认是空格或者tab制表符
命令体:
读前处理:BEGIN{命令...}------->页眉
所有行处理:{命令...}------->内容
读后处理:END{命令...}------->页脚
例如: awk -F: 'BEGIN{...;}{...;}end{...;}' testfile
2、内建变量、定址
注意:内建变量不需要用$取值
NR:awk读入的所有文件的行号
FNR:awk当前读入的行在当前文件的行号(如果从多个文件读取时,该变量FNR和NR就不同了)
FILENAME:文件名
NF:字段个数
FS:以变量方式指定分割符,-F是以参数方式指定分割符
OFS:指定字段输出的分割符
ORS:指定行输出的分割符
awk -F: 'NR==3 {print $1,$7}' pass
awk -F: '{print FILENAME,NR,FNR,$1,$7}' pass pass2
awk -F: '{print NF,FILENAME,NR,$0}' pass
awk -F[:/] '{print NF,FILENAME,NR,$0}' pass
awk -F[^a-Z] '{print NF,FILENAME,NR,$0}' pass
awk 'FS=":" {print $1,$7}' pass
awk -F: 'OFS="----" {print $1,$7}' pass
awk -F: 'ORS="|||" {print $1,$7}' pass
正则定址
awk -F: '/root/ {print $1,$7}' pass
awk -F: '/ro+/ {print $1,$7}' pass #awk默认支持拓展正则
3、awk运算符
比较运算符
awk -F: 'NR!=3 {print $1,$7}' pass
awk -F: 'NR<=3 {print $1,$7}' pass
awk -F: '$1~/ro/ {print $1,$7}' pass
awk -F: '$7~"sh$" {print $1,$7}' pass
awk -F: '$7!~"sh$" {print $1,$7}' pass
awk -F: 'NR>3&&NR<6 {print $1,$7}' pass #3-6行
awk -F: 'NR<3 || NR>6 {print $1,$7}' pass
算术运算符
awk -F: '$3=$3+1 {print $1,$3}' pass
awk -F: '$3++ {print $1,$3}' pass
awk -F: '$3+=1 {print $1,$3}' pass
awk -F: '$3%2==0 {print $1,$3}' pass
awk -F: '$3=$3**2 {print $1,$3}' pass
转义字符
awk -F: '{print $1"\t"$3}' pas
awk -F: '{print $1"\b"$3}' pass
二、awk高级知识
awk的语法与C语言非常类似,很容易学习!
1、if-else分支
awk -F: '{if($3==10) print $0}' pass
awk -F: '{if($3==10) {print $1;print $7}}' pass #嵌套,如果只有一个语句,{}可加可不加,"{}"后不可有";"。
awk -F: '{if($3==10) {print $1;} else print $0}' pass #if-else
#if-else if-else,注意:匹配字符串的时候要加引号"root"
awk -F: '{if($3==10) {print $1;} else if($1=="root") print $0; else print $7;}' pass
例如:如果UID=0,打印admin;UID在1~499之间打印sys_users;UID在500以上打印users
awk -F: '{
if($3==0) {
} else if($3>=1&&$3<500) {
else {
}
}' /etc/passwd
2、三目运算符
expr?act1:act2
awk -F: 'var=($3==0)?"admin":"users" {print $1,var}' /etc/passwd
awk -F: '($3==0)?var="admin":var="users" {print $1,var}' /etc/passwd #结果同上
awk -F: '{print ($3>500)?:$1:$6}' /etc/passwd
3、格式输出printf
使用printf很方便打印出整齐的格式,和C语言printf很相似!!
格式:printf "...",...,...,...;
例如:printf "%d %s %s\n",$3,$1,"aaa";
]#打印出结果,如果不够5个字符,在左侧补空格
awk -F: 'BEGIN{printf "%-7s %-15s %-4s\n","UID","NAME","LEVEL"}{printf "%-7s %-15s %-4s\n",$3,$1,$4} END{print NR,NF,FILENAME}' /etc/passwd
#打印出UID,NAME,LEVEL
4、awk的语句段执行过程
BEGIN:该阶段还未处理文件,常用于做变量初始化工作
{}:开始处理文件,每处理一行执行一次{}内的语句!
END{}:处理完文件的善后工作。
注意以下运行结果:
awk 'BEGIN{FS=":"} {print $1}' /etc/passwd #正确
awk 'FS=":" {print $1}' /etc/passwd
统计行数
awk 'BEGIN{i=0}{i++}END{print "lines "i}' /etc/passwd
lines 40
计算UID、GID之和
awk -F: 'BEGIN{usum=0;gsum=0;i=0}{i++;usum=usum+$3;gsum=gsum+$4}END{printf "%-10s%-10d%-10s%d\n","UID_SUM:",usum,"GID_SUM:",gsum;printf "%-10s%-10d%-10s%-10d\n","UID_AVG:",usum/i,"GID_AVG:",gsum/i}' /etc/passwd
统计程序的虚拟内存和实际内存
ps aux|grep -v '^USER'|awk 'BEGIN{vsz=0;rss=0}{vsz=vsz+$5;rss=rss+$6}END{printf "%-5s%-10d%-5s%-10d\n","VSZ:",vsz/1024,"RSS:",rss/1024}'
5、while循环
awk 'BEGIN{i=0;while(i<10){print i++}}'
6、do while循环
awk 'BEGIN{i=5;do{print i++}while(i<4)}' #先执行,后判断
7、for循环
awk 'BEGIN{for(i=0;i<10;i++) print i}'
例如:打印99乘法表
awk 'BEGIN{for(i=1;i<10;i++) {for(j=1;j<=i;j++) {printf "%d%s%d%s%d\t",j,"*",i,"=",i*j;}printf "\n"}}'
逆序输出passwd
awk -F: '{for(i=NF;i>=1;i--){printf "%s",$i;if(i!=1) printf ":";} printf "\n"}' /etc/passwd
8、break、continue
awk 'BEGIN{for(i=1;i<=5;i++) {if(i>3) break;print i}}'
awk 'BEGIN{for(i=1;i<=5;i++) {if(i==3) continue;print i}}'
9、next、exit
awk -F: 'NR>3{next}{print $i}END{print NR}' /etc/passwd #当NR>3时,继续扫描余下的行,但不执行print $i,
awk -F: 'NR>3{exit}{print $i}END{print NR}' /etc/passwd #当NR>3时,停止扫描
10、数组
awk的数组功能很强,下标不一定是数组
awk 'BEGIN{ary[1]="seker";ary[2]="yerik";print ary[1],ary[2]}'
awk 'BEGIN{ary[1]="seker";ary[2]="yerik";for (i in ary) print i,ary[i]}' #for必须有(),注意与shell的区别
awk 'BEGIN{for(i=1;i<=10;i++){ary[i]=i} for(i in ary) print ary[i]}' #注意:打印出来的结果是无序的,因为是并行输出的
用非数字作为数组下标(这点是其他大部分高级语言所不具备的)
awk -F: '{ary[$1]=$6;} END{for(i in ary) print i,ary[i]}' /etc/passwd
例如:统计用户的shell
awk -F: '{ary[$NF]++}END{for(i in ary)print ary[i],i }' /etc/passwd #注:个人认为此用法相当犀利!!!在统计时多用!!!
同awk -F: '{if(ary[$NF]==0) ary[$NF]=1;else ary[$NF]++}END{for(i in ary) print ary[i],i}' /etc/passwd
11、awk脚本
使用脚本后,适当的缩进增加程序可读性;
<1> 引用awk文件
awk -F: -f awk.sh /etc/passwd
awk.sh脚本内容
1 {ary[$NF]++}
2 END{
3
4
5 }
<2> 用awk解释器解释脚本
1 #!/bin/awk -f
2 BEGIN{
3
4 }
5
6 {ary[$NF]++}
7 END{
8
9
10 }
<3> awk 与shell共存(awk引用shell的变量)
方法一(屏蔽shell的解释):
#!/bin/bash
var=root
awk -F: '$1~/'$var'/ {print $0}' /etc/passwd
#awk 的引号''是为了屏蔽shell的解释,而要想让awk解释shell的变量,可以在awk中将变量用引号''引起来
方法二(变量作为awk的参数):
#!/bin/bash
a=root
awk -v var=$a -F: '$1==var {print $0}' /etc/passwd
###############################
三、awk练习
1.使用:或/符号做分隔符,将字段逆序输出/etc/passwd文件的每行
awk -F: '{for(i=NF;i>=1;i--) if(i==1)printf "%s\n",$i;else printf "%s:",$i}' /etc/passwd
2.观察两个文件,以及join命令输出,用awk引入name.txt,home.txt两个文件,模拟joni命令的输出
# awk -F: 'NR < 11 {print $3,$1}' /etc/passwd > name.txt
# awk -F: 'NR < 11 {print $3,$6}' /etc/passwd > home.txt
# join name.txt home.txt
awk '{ary[$1]=$2" "ary[$1]}END{for(i in ary) print i,ary[i]}' name.txt home.txt|sort -n
3.统计/etc/passwd中每种shell的被使用人数
输出格式:
counts shell
1
1 /bin/sync
4 /bin/bash
31 /sbin/nologin
1 /sbin/halt
1 /sbin/shutdown
awk -F: '{ary[$7]++}END{for(i in ary) print ary[i],i}' /etc/passwd
4.统计ps中RSZ,VSS各自总和
输出格式:
ps MEM statistic
VSZ_SUM : 164.277M
RSS_SUM : 47.8555M
ps aux|grep -v '^USER'|awk 'BEGIN{vsz=0;rss=0}{vsz=vsz+$5;rss=rss+$6}END{print "VSZ_SUM :",vsz/1024"M";print "RSS_SUM :",rss/1024"M"}'
VSZ_SUM : 2187.08M
RSS_SUM : 417.352M
5.计算/etc/passwd中所有用户的UID平均数,以及GID平均数.
输出格式:
UID and GID AVG
UID-AVG : 1750.72
GID_AVG : 1754
awk -F: 'BEGIN{print "UID and GID AVG"; u_sum=0;g_sum=0}{u_sum+=$3;g_sum+=$4}END{print "UID-AVG :",u_sum/NR;print "GID_AVG :",g_sum/NR}' /etc/passwd
UID and GID AVG
UID-AVG : 1710.88
GID_AVG : 1714.12
6.
根据uid值给用户分等级 Admin system users
输出格式:
LEVEL NAME
Admin root
sysuser bin
users seker
admin_count: N sys_user_count: N users_count: N
awk -F: 'BEGIN{printf "LEVEL\tNAME\n"}{if($3==0) {printf "Admin\t%s\n",$1;admin++}else if($3>=500) {printf "users\t%s\n",$1;user++}else {printf "sysuser\t%s\n",$1;sysuser++}}END{printf "admin_count:%d\tsys_user_count:%d\tusers_count:%d\n",admin,user,sysuser}' /etc/passwd
-------------------------------
7.分别用GREP,SED,AWK将ifconfig中匹配到eth1的网卡所有信息打印出来.
ifconfig|awk -F"\t" '$1==lo{exit}{print $1"\t"$2}'
-------------------------------
8.SHELL实现批量建立多个文件,将文件拓展名加上.txt,再加上.doc,再把中间的.txt去掉
1 #!/bin/bash
2
3 NEWNAME=""
4 echo "Touching TXT Files..."
5 sleep 1
6 touch {a,b,c}_{1,2,3}.txt
7 echo $(ls *.txt)
8 echo
9
10 for i in $(ls *.txt)
11 do
12
13 done
14 echo "txt.doc Files:"
15 sleep 1
16 echo $(ls *.doc)
17
18 for i in $(ls *.doc)
19 do
20
21
22 done
23 echo
24 echo ".doc Files:"
25 sleep 1
26 echo $(ls *.doc)
27 exit 0
9.AWK脚本实现间隔五行打印表头
# ./awk_print.sh /etc/passwd
Username Uid
root
bin
daemon
adm
lp
Username Uid
shutdown 6
halt
mail
news
uucp
1 #!/bin/awk -f
2
3 BEGIN{FS=":";}
4 {
5
6
7
8
9
10 }
1 #!/bin/awk -f
2
3 BEGIN{i=1;max=0;min=0;tmp=0}
4
5 {ary[i++]=$1;}
6
7 END{
8
9
10
11
12
13
14
15
16
17
18 }
转自:http://hi.baidu.com/googleu/blog/item/1d3be02b13b38290033bf6ce