Centos 6.6上awk命令的简单使用

分类:CentOS教程 阅读:80406 次

本文实验环境:vmware workstation 10 +Centos6.6 X86_64,文中命令请谨慎使用。

AWK是类UNIX操作系统中一款文本处理工具,同grep,sed并成为文本处理三剑客,使用上的侧重点为:生成格式化的文本报告,但awk有丰富的语法和灵活的变量,称其为一门独立的语言也不为过。下文仅仅是awk生成格式化文本报告功能的简单使用。

1.awk工作过程描述:

awk将被处理的文件,逐行读入;按照输入分隔符,对改行进行分割处理;分割后的行内容块的索引从1开始,索引0为整行内容;根据定义的处理方式对行内容进行匹配,若匹配条件,则以合适的格式打印相应的行数据块,若行数据不匹配相应条件,则不处理。

2.awk语法格式

对awk来说很难总结出一个完全适应任何场合的语法格式,就生成格式化文本报告功能来说可以勉强写为下面的:

$awk [option] '[PATTERN] { ACTION STATEMENT }' file

option:

经常用到的有2个:

-F PUNCT:指定输入分隔符。

-v VAL_NAME=VALUE:自定义变量值。下文有例子说明。

其它的部分,请根据下面的例子进行学习,文末尾再进行总结。

3.例子教学:

3.1)打印/etc/passwd文件中root用户条目的用户名,uid和shell。

先取出/etc/passwd文件中root用户的条目

可以看到关于root用户的条目处理时使用“:”为分隔符是个明智的选择,用户名在第一部分,uid在第三部分,shll在第七部分,所以可以使用awk这样来写,就满足题意:

上述awk表达式中,使用-F指定输入分隔符为“:”; ACTION为 print,就是打印的意思, STATEMENT是 $1,$3,$7

当然也可这样写:

总结一:ACTION: print

print:

格式:
print item1,item2,...
要点:
1)各item间使用逗号分隔,而输出时使用输出分隔符分隔,输出分隔符默认为空格。
2)输出的各item为字符串,数值和当前记录的字段($n),变量的值或awk的表达式,
数值会被隐式转换为字符进行输出。
3)print后面的item如果省略,相当于print $0;输出空白 相当于print " "

上述2种awk表达方式可以完成题目的要求,但是输入的内容不是很美观,可以使用printf 代替print 来打印输出格式:

"USERNAME:%-s\nUID:%-d\nSHELL:%-s\n" 是格式符,因后边有3个部分要打印,故这里给出了3个格式符,USERNAME:%-s\n是针对第一个item即题目中的要打印的用户名,UID:%-d\n是针对第二个item即题目中的要打印的UID,SHELL:%-s\n针对的是第三个item即用户的shell。并且每个格式符中明确指定了换行符\n

虽然好看了,但是awk表达式也复杂起来,下面就总结下ACTION中printf的使用:

总结二:ACTION:printf:
格式:
printf format,item1,item2,...
要点:
1)printf中format称为格式符,是必须的,需明确给出
2)不会自动换行,需显示指定换行符\n
3)format中需要分别为后面每一个item指定一个格式符

格式符:都以%开头,后跟一个字符
%c:显示字符ASCII码,其实显示字符本身
%d %i:显示十进制格式的整数
%e %E:科学计数法显示数值
%f:显示浮点数
%g %G:以科学计数法格式或浮点数格式显示数值
%s:显示字符串
%u:显示无符号整数
%%:显示%自身
格式的修饰符:
#[.#]:第一个#为数字,显示宽度,后边.#在表达浮点数时表示精度
-:左对齐,默认右对齐
+:显示数值的符号, 正负数

3.2)使用"#"为连接符,显示系统上root用户的名称,uid和shell的设定

总结三:awk变量:FS为行输入分隔符,OFS为行输出分隔符,使用-v val_name=value来定义,-F PUNCT也是指定输入分隔符的,二者默认为空格。

3.3)打印/etc/passwd文件中用户名为一行

因awk是逐行对文件进行处理的,故/etc/passwd文件中每行的$1就是用户名,但是对输出换行符不进行指定的话,打印出来是这个样子:

因此需要指定输出换行符,这样才可将/etc/passwd文件中用户名打印为一行

总结三:awk变量:RS为awk输入换行符,ORS为输出换行符,使用-v val_name=value来定义

3.4)显示/etc/passwd中第一行有几个字段,并打印最后那个字段

总结三:awk变量:NF为当前行可被分割的成几个字段,$NF为被分割后最后那个字段,需指明行分隔符,默认为空格。

3.5)打印显示/etc/issue和/etc/sysconfig/network的行和行号,仔细观察下面三段显示的不同

总结三:awk变量:一行命令中同时处理多个文件时,NR:后边要处理的文件的行进行统一计数,显示当前行的行号。FNR:后边每个要处理的文件的行数单独计数时,显示当前行的行号。FILENAME:当前被处理的文件的文件名。

3.6)

(1)打印显示/etc/passwd文件中普通用户的信息

在centos6.6上系统中的匹配用户的uid从500开始的,故这里只需打印/etc/passwd文件中uid列大于等于500的用户行即可

这里用到可行模式匹配,即awk语法格式中的pattern的定义。

总结四:PATTERN:

关系表达式,即上例中的'$3>=500

涉及到比较操作符: >,>=,< ,<=,==,!=

(2)使用ifconfig eth1显示eth1网卡的配置信息,抓取ip地址所在的行

因IP地址所在的行在第二行,故借助NR可以抓取出来。

3.7)显示/etc/passwd文件中root用户行信息

因在/etc/passwd文件每一行开头的都是用户名,故抓取root开头且为独立单词的行即可,正则表达式为^root\>

总结四:PATTERN:

/regular expression/:仅处理能被/regular expression/匹配的行

上述例子中root若不加词尾锚钉,会出现下列现象:

3.8)显示/etc/passwd文件中root开头的行至shutdown开头的行之间的内容

总结四:PATTERN:

line rangs:行范围,类似于sed 或vim 中的定界符,startline,endline

3.9)打印系统上shell为bash的用户,开始和结束要有明确提示:

总结四:PATTERN:

BEGIN:同要处理的文件内容没关系,只是在所有awk动作之前执行一个动作
END:在awk所有的动作结束后,执行的动作

3.10)显示系统中的用户uid在0与100之间的用户

因用户的UID在/etc/passwd文件中第3部分,因此只要对/etc/passwd文件使用":"为输入行分隔符,抓取第三部分进行条件过滤即可实现

总结五:awk中的控制语句if;

格式:

if(condition){statement1;statement2;...}[else {statement1;statement2;...}]
当 statement只有一个时,{}可以被省略
单分支if语句时 {}可省略

上面的例子中if语句相当于2个if语句的嵌套,若写成bash脚本格式如下:

if [ $3 -gt 0 ];then

if [ $3 -lt 100 ];then

echo .....

fi

fi

awk中是不是不用写关闭符很爽,不用写bash脚本那样死板的格式很爽,那就去玩玩python吧,python的脚本写着同样很爽,至少比bash 爽。

3.11)显示/etc/inittab文件第一句中每个字段的长度

总结五:awk中的控制语句:while

格式:
while(condition){statment1;statment2;...}
条件为真时循环,直到为假时退出;
通常用于在当前行的各字段间进行循环。

在上面的awk语句中定义了变量i,NF为awk内置变量表示当前行可被分割成的字段数,当变量i<=NF为真时,while循环启动,显示$i为index的字段,length($i)为字段的长度,让后用i++自加,指导i<=NF为假时,停止while循环,停止打印。

上面的例子使用另外一种格式来实现:

总结五:awk中的控制语句:for

格式:

for:
for(expr1;expr2;expr3) statement
expr1:变量初始值
expr2:条件
expr3:变量变化

3.12)打印/etc/passwd中uid为奇数的用户条目

另外一种写法:

总结五:awk中的控制语句,中特殊关键字:

next:提前结束对本行的处理,而进入下一行的处理

break:跳出当前循环

continue:提前结束本轮循环,进入下一轮循环

在上面的例子中使用$3%2:$3对2取模,就是求余数,若余数为0,则被除数$3为偶数,若余数不为0则被除数$3为奇数。

3.13)统计当前OS的tcp连接状态和状态的个数

显示os的tcp连接状态:

可以看到左边第一列就是tcp的连接状态,但是第一行要去掉。

总结六:awk的数组:

格式:array_name[index-expression]

awk中的数组是关联数组,有的编程语言如python中会称关联数组为字典。
index-expression:可以使用任意字符串;
如果某数组元素不存在,在引用时,awk会自动创建该元素并将其初始化为空串
在数组中遍历每一个元素:使用 for(var in array){for body}
var会遍历array的每一个索引,print array[var]显示该索引代表的值

上面的例子中使用/^State/,这个正则表达式匹配#ss -tan的第一行,使用!/^State/ 表示对这个模式取反,即要处理不以State开头的行。定义了关联数组connect[],使用$1为数组的index值,处理每一行时,若connect[$1]存在则数字加1,若connect[$1]不存在则创建。awk动作结束后,使用for语句来处理,上例中i代表connect数组的index,connect[i]则为该index对应的值。

总结七:awk的内置函数处理字符串时使用:
字符串处理:

length([s]):返回指定字符串的长度
sub(r,s[,t]):以r所代表的模式来查找t字符串中的匹配,将其第一次出现替换同s所表示的字符串
#awk -F:'{sub(root,ROOT,$0)}' /etc/passwd

gsub(r,s[,t]):以r所代表的模式来查找t字符串中的匹配,将所有出现替换为s所表示的字符串
split(s,a[,r]):以r为分隔符切割字符串s,并将切割的结果保存至数组a中,
len=split(s,a[,r])为被切割后的段数

#netstat -tan|awk '/^tcp/{len=split($5,count,":");ip[count[len-1]]++}END{for(i in ip){print i,ip[i]}}'

<统计连接中,Foreign Address出现的次数>
substr(s,i[,n]):从s表示的字符串中取子串,从i开始,取n个字符

4 awk实际应用举例:

4.1)取出当前网卡eth1的ipv4地址:

eth1地址格式:

处理方式:

说明:-F '[ :]+' 指定输入行分隔符为 空格和':',+表示出现的次数至少1次,

inet addr : 192.168.100.2 。。。。

第一列 第二列 第三列 第四列 忽略

NR表示当前处理的行在文件中的位置行号。

若还是不明白,自己动手试试or画个圈圈诅咒自己的智商吧!

4.2)统计下面apache access日志中给出的ip地址和访问次数

处理方式:

这个就不用说了吧,只是awk管理数组和sort的联用,简单的有点可耻。

4.3)打印当前系统上,磁盘分区使用超过10%的分区的分区名,可使用空间和挂载点: