shell之awk


AWK
一、awk基础知识

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      #打印第3行
awk -F: '{print FILENAME,NR,FNR,$1,$7}' pass pass2   #NR是所有文件的行号,FNR是当前读入文件的行号,FILENAME文件名
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       #第一列匹配ro,被匹配的部分需要用""或//,支持正则
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      #$3的平方

转义字符
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) {
   print $1"\tadmin";
} else if($3>=1&&$3<500) {
   print $1"\tsys_users"}
else {
   print $1"\tusers";
}
}' /etc/passwd


2、三目运算符
expr?act1:act2
awk -F: 'var=($3==0)?"admin":"users" {print $1,var}' /etc/passwd   #如果UID=0则打印出admin,否则打印user,下同
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";   #注意:printf默认不换行

]#打印出结果,如果不够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{
        for(i in ary)
                print ary[i],i;
5 }

<2> 用awk解释器解释脚本
1 #!/bin/awk -f
2 BEGIN{
        FS=":"
4 }
5
6 {ary[$NF]++}
7 END{
        for(i in ary)
                print ary[i],i;
10 }


<3> awk 与shell共存(awk引用shell的变量)

方法一(屏蔽shell的解释):
#!/bin/bash
var=root
awk -F: '$1~/'$var'/ {print $0}' /etc/passwd   #此处awk引用了shell的var变量
#awk 的引号''是为了屏蔽shell的解释,而要想让awk解释shell的变量,可以在awk中将变量用引号''引起来

方法二(变量作为awk的参数):
#!/bin/bash
a=root
awk -v var=$a -F: '$1==var {print $0}' /etc/passwd   #-v参数用来让awk接受shell的变量


###############################
三、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         mv $i "$i.doc"
13 done
14 echo "txt.doc Files:"
15 sleep 1
16 echo $(ls *.doc)
17
18 for i in $(ls *.doc)
19 do
20         NEWNAME=$(echo $i|awk -F. '{printf "%s.%s",$1,$3}')
21         mv $i $NEWNAME
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      0     
bin       1     
daemon    2     
adm       3     
lp        4     

Username Uid   
shutdown 6     
halt      7     
mail      8     
news      9     
uucp      10    

1 #!/bin/awk -f
2
3 BEGIN{FS=":";}
4 {
        if((NR-1)%5==0){
                printf "\n%-10s%-10s\n","Username","Uid";
                printf "%-10s%-10s\n",$1,$3;
        }else
                printf "%-10s%-10s\n",$1,$3;
10 }

1 #!/bin/awk -f
2
3 BEGIN{i=1;max=0;min=0;tmp=0}
4
5 {ary[i++]=$1;}
6
7 END{
        for(i=1;i<=99;i++){
                for(j=1;j<=99;j++){
10                         if(ary[j]>ary[j+1]){
11                                 tmp=ary[j];
12                                 ary[j]=ary[j+1];
13                                 ary[j+1]=tmp;
14                         }
15                 }
16         }   
17         for(k in ary) print ary[k];
18 }



转自:http://hi.baidu.com/googleu/blog/item/1d3be02b13b38290033bf6ce.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值