awk:报告生成器

格式化后显示信息

by www.linuxfan.cn 2016.1.23

http://os.51cto.com/art/201003/187533.htm

语法:

awk [options] 'script' file1 file2, ...

awk [options] 'PARTTERN { action }' file1 file2, ...

最常见的action:print,printf

awk的基本特征:

a.每一次取一行

b.根据指定的分隔符(不指定是位空白字符)将该行切割位列,使用$0(整行),$1,$2,$3...(第一列,第二列,...)

c.可以指定行号,列号,切割符,操作后分隔符

案例:

chkconfig --list |grep 3:启用 |awk '{print $1}' ##查看在运行级别为3开机启动的服务,打打印出第一列

clip_image002[18]

tail -1 /etc/passwd |awk -F ':' 'BEGIN{OFS="---"}{print $1,$6,$7}' ##OFS(光纤传感器)指定输出分隔符

clip_image004[15]

ifconfig eth1 |awk -F '[ :]+' 'NR==2 {print $4}'

clip_image006[15]

ifconfig eth1 |awk -F '[ :]+' 'NR==2 {print "eth1_ip="$4}' ##可以加入显示内容

awk 'BEGIN {print "line one \nline two\nline three"}'

clip_image008[15]

4.高级awk的使用:

1)awk变量:

FS:列分隔符,默认位空白

RS:行分隔符,默认位换行符

OFS:输出列分隔符

ORS :输出行分隔符

2)awk内置变量

NR:处理中行数

FNR:单个文件的行数

NF:列的个数

案例:

ifconfig eth1 |awk '{print NR}'

clip_image010[15]

ifconfig eth1 |awk '{print NF}'

clip_image012[15]

3)自定义变量:

awk 'BEGIN{test="www.linuxfan.cn";print test}'

clip_image014[15]

awk -v test="linuxfan.cn" 'BEGIN{print test}'

clip_image016[13]

4)printf

使用的格式:

printf format, item1,item2, ...

特征:

a.必须指定format,用于指定后面item的输出格式

b.printf语句不会自动打印换行符:\n

c.format格式以%+一个字符,如下:

%c:显示字符的ASCII码

%d,%i:十进制整数

%e:科学计数法显示数值

%f:显示浮点数(小数)

%s:显示字符串

%u:无符号整数

%%:显示%

d.修饰符:N:显示宽度,-:左对齐,+:显示数值符号,如%-c(左对齐)

案例:

chkconfig --list |grep 3:启用 |awk '{printf "%-10s",$1}' ##在统一行显示

clip_image018[13]

awk -F : '{printf "%-15s %-10d %-10s\n",$1,$3,$7}' /etc/passwd

clip_image020[11]

5)awk的操作符

a.算数操作符

-x负值

+x转换为数值

x^y

x**y 次方

x*y

x/y

x+y

x-y

x%y

b.赋值操作符

=

+=

-=

*=

/=

%=

++变量加1

--变量减1

c.布尔值

awk中,任何非0值或者非空字符串都为真,反之为假

d.比较操作符:>,<,>=,<=,==,!=,~,!~(x ~ y,字符串能被表达式y匹配)

d.逻辑操作符:&&,||,!

e.条件表达式:条件?if-true-exp:if-false-exp

f.调用函数:function_name (pa1, pa2)

6)awk常见的模式类型:

a.正则表达式(regexp),格式为:/regular expression/

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

clip_image022[11]

http://baike.baidu.com/link?url=OoIlUvN0Im2vVQpksjqMbn0GzIdJaomETS3QnChMCMbxbczH41jEw6ynyk95dos4PLye963SqvwfIu4RziuDxq

b.表达式(expression),值为非0或为非空时满足条件,如$1 ~ /foo/或 $1 == "root"

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

clip_image024[11]

awk -F : '$3+1<=100&&$3+1>=10{print $1,$3,$7}' /etc/passwd

clip_image026[11]

awk -F : '$2=="!!"{print $1,$2}' /etc/shadow ##检查未初始化密码的用户

clip_image028[11]

passwd -d u01

clip_image030[11]

awk -F : '$2==""{print $1}' /etc/shadow ##打印密码为空的用户

clip_image032[11]

awk -F : '$7~"bash$"{print $1,$3,$7}' /etc/passwd ##匹配$7为bash结束行

clip_image034[11]

awk -F : '$7!~"bash$"{print $1,$3,$7}' /etc/passwd

c.匹配范围(ranges),指定的匹配范围,格式为part1,part2

awk -F : '$3==3,$3==10{print $1,$3,$7}' /etc/passwd

clip_image036[11]

awk -F : '$1=="root",$1=="adm"{print $1,$3,$7}' /etc/passwd

clip_image038[11]

awk -F : '/^r/,/^a/{print $1,$3,$7}' /etc/passwd

clip_image040[11]

d.特殊模式(BEGIN/END)

awk -F : 'BEGIN{printf "%-10s%-10s%-20s\n","UserName","ID","Shell"}{printf "%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd ##在awk处理之前打印头部BEGIN{}

clip_image042[11]

awk -F : 'BEGIN{printf "%-10s%-10s%-20s\n","UserName","ID","Shell"}$7~"bash$"{printf "%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd ##多个模式混合使用

clip_image044[11]

awk -F : 'BEGIN{printf "%-10s%-10s%-20s\n","UserName","ID","Shell"}$7~"bash$"{printf "%-10s%-10s%-20s\n",$1,$3,$7}END{print "End of report"}' /etc/passwd ##在awk执行完成后打印尾部END{}

clip_image046[11]

awk -v i=1 '$5~"yum"{i++}END{print "yum use times:", i}' /var/log/messages

clip_image048[11]

/正则表达式/:使用通配符的扩展集合。

关系表达式:如字符串或数字的比较。

模式匹配表达式:模式(指定一个行的范围,不包含BEGIN,END)

7)常见的action:(功能)

expressions:表达式

control satatements:控制语句

compound statements:混合语句

input statements:输入语句

output statements:输出语句

8)action中的控制语句:

a.if-else

语法:if (condition) command action1; else command action2

案例:

awk -F : '$7~"bash"{if ($1=="root") print $1, "admin";else print $1, "Common User"}' /etc/passwd

clip_image050[11]

awk -F : -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd

clip_image052[11]

awk -F : -v sum=0 '$7~"bash"{if ($1=="root") print $1, "admin" sum++;else print $1, "Common User" sum++}END{print "can login user num:",sum}' /etc/passwd ##二合一

clip_image054[11]

awk -F : '$7~"bash$"{if ($1=="root") printf "%-15s: %s\n",$1,"admin";else printf "%-15s: %s\n",$1,"common user"}' /etc/passwd ##格式化输出

clip_image056[11]

b.while循环:循环字段,awk本身就是行的循环

语法:while (condition){statement1;statement2;...}

案例:

awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd ##循环打印前3列

clip_image058[11]

awk -F : '{i=1;while (i<NF) {if (length($i)<=4) print $i;i++}}' /etc/passwd ##循环整行,并打印出长度小于4的字段列

clip_image060[11]

c.do-while

语法:do {statement1;statement2;...} while (condition)

awk -F : '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd

clip_image062[9]

d.for

语法:for (variable assignment;condition;iteration process){statement1, statement2,...}

案例:

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

clip_image064[9]

for循环遍历数组元素:

语法:for (i in array) {statement1, statement2,...}

案例:

awk -F : '{SH[$NF]++;}END{for (i in SH){print i,SH[i]}}' /etc/passwd

clip_image066[9]

netstat -ant |awk '/^tcp/{++S[$NF]}END{for(a in S) print a, S[a]}'

clip_image068[7]

awk '{counts[$1]++}END{for (url in counts) print url,"access times:",counts[url]}' /var/log/httpd/access_log

clip_image070[7]

awk '{S[$5]++}END{for (i in S) print i,S[i]}' /var/log/messages

clip_image072[7]

awk '{AH[$1]++}END{for (i in AH) printf "%-20s:%s\n", i, AH[i]}' /var/log/httpd/access_log

clip_image074[7]

9).awk中的数组

array[index-expression]

index-expression可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用index in array的方式。要遍历数组中的每一个元素,需要使用如下的特殊结构:

for (var in array) { statement1, ... }

例如:

state[abc]=3

state[efg]=6

for (A in state) {print A,state[A]} ##A一定是index-expression(下标abc/efg),state[A]是一个具体的值(3/6)

[root@localhost ~]# netstat -ant

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address Foreign Address State

tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN

tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN

tcp 0 0 192.168.1.106:22 192.168.1.101:36318 ESTABLISHED

clip_image076[7]

以上命令显示的结果中,每一行最后一个字段为状态,若要统计每种状态的个数,只需要将state作为数组下标,由于awk本身就是一个行的循环,所以只需要给数字自加1(++)即可实现统计,具体操作如下:

netstat -ant |awk '{S[$6]++}END{for(i in S){print i,S[i]}}'

clip_image078[7]

10)awk的内置函数

split(string,array[filedsep[,seps]])

作用:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的数组中;数组下标为从0开始的序列;

# netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50

clip_image080[7]

for i in $(awk -F : '$7~"bash$"{if($3 > 1 && $3 < 500) print $1}' /etc/passwd);do chsh -s /sbin/nologin $i;done

clip_image082[7]

awk脚本分享:

1.计算cpu占用:

[root@www ~]# cat pcpu_usage.sh

#!/bin/bash

#用途:计算1个小时内进程的CPU占用情况

SECS=3600

UNIT_TIME=60

#将SECS更改成需要进行监视的总秒数

#UNIT_TIME是取样的时间间隔,单位是秒

STEPS=$(( $SECS / $UNIT_TIME ))

echo "Watching CPU usage..."

for ((i=0;i<STEPS;i++));do

ps -eo comm,pcpu |tail -n +2 >>/tmp/cpu_usage.$$

sleep $UNIT_TIME

done

echo

echo "CPU eaters :"

cat /tmp/cpu_usage.$$ | \

awk '

{ process[$1]+=$2; }

END{

for(i in process)

{

printf("%-20s %s",i,process[i]);

}

}' |sort -nrk 2 |head

rm /tmp/cpu_usage.$$

[root@www ~]#

clip_image084[5]

2.统计10条最常用的命令:

[root@www ~]# cat top10_command.sh

#!/bin/bash

##用途:列出10条最常使用的命令

printf "COMMAND\tCOUNT\n" ;

cat ~/.bash_history |awk '{ list[$1]++; } \

END {

for (i in list)

{

printf("%s\t%d\n",i,list[i])

}

}' |sort -nrk 2 |head

[root@www ~]#

clip_image086[5]

http://stlong.blog.51cto.com/5144113/1680855