您的位置:首页 > 运维架构 > Linux

Linux的文本三剑客(grep sed awk) —— awk的介绍

2018-08-29 21:34 866 查看
一、三剑客简介
grep: 文本过滤工具, (grep,egrep,fgrep) 文本搜索工具,根据用户指定的“模式”对目标文件逐步进行匹配检查,打印匹配到的行。
sed: 文本编辑工具,实现数据的替换,删除,增加,选取等(以行为单位进行处理)。
awk: 文本报告生成器,以字段为单位进行处理(把一行的数据分割,然后进行处理)。
本文只介绍awk。

awk的介绍
1. awk的简介
awk不仅是linux系统中的一个命令,还是一种编程语言,可以用来处理数据和生成报告(excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。
awk的应用里最重要的一个功能就是计数,而数组在awk里最大的作用就是去重复。
2. awk的格式
awk指令是由模式,动作,或者模式和动作的组合组成。
awk [options] 'pattern{print} ' file
模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。





注意:
pattern和{action}需要用单引号引起来,防止shell作解释。
pattern是可选的。如果不指定,awk将处理输入文件中的所有记录。如果指定一个模式,awk则只处理匹配指定的模式的记录。
{action}为awk命令,可以是但个命令,也可以多个命令。
整个action(包括里面的所有命令)都必须放在{ }内。
action必须被{ }包裹,没有被{ }包裹的就是patern
file要处理的目标文件
3. awk工作原理
awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成。

第一步:执行BEGIN{action;… }语句块中的语句。
第二步:从文件或标准输入读取一行,然后执行pattern{ action;… }语句块,逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块。
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
&nb
5b28
sp; 4. 记录与字段
awk对每个要处理的输入数据认为都是具有格式和结构的,而不仅仅是一堆字符串。默认情况下,每一行内容都是一条记录,并以换行符分隔(\n)结束。
简单来说: 记录 = 行
字段,域 = 列

小结:
RS 记录分隔符,表示每行的结束标志
NR 行号(记录号)
FS 字段分隔符,每列的分隔标志或结束标志
NF 就是每行有多少列,每个记录中字段的数量
$ 符号表示取某个列(字段),$1$2$NF
NF 表示记录中的区域(列)数量,$NF取最后一个列(区域。)
FS(-F)字段(列)分隔符,-F(FS)“:”<==>‘BEGIN{FS=':'}’
NR 行号
分隔符==>结束标识
5. awk变量

1,内置变量

FS:输入字段分隔符

awk -v FS=':' '{print $1,$3}' /etc/passwd
先找一个文件/etc/passwd作为参数,这样可查看命令的结果。




OFS:输出字段分隔符

awk -v FS=':' -v OFS=':' '{print $1,$3}' /etc/passwd



RS:输入的记录分隔符

awk -v FS="." -v RS=" " '{print $1}' chen



ORS:输出的记录分隔符

awk -v FS="." -v RS=" " -v ORS="#" '{print $1}' chen



NF:字段的数量

awk -F" " '{print NF}' /etc/fstab





NR:记录号

awk '{print NR,$0}' /etc/fstab



FNR:各文件分别计数,行号

awk '{print FNR}' /etc/fstab /etc/inittab



FILENAME:当前文件名

awk '{print FILENAME}’ /etc/fstab



ARGC:命令行参数的个数

awk '{print ARGC}' /etc/fstab  /etc/shadow



ARGV:数组,保存的是命令行所给定的各参数

awk 'BEGIN {print ARGV[2]}'  /etc/fstab /etc/inittab



打印命令行的最后一个参数

awk 'BEGIN {print ARGV[ARGC-1]}'  /etc/fstab /etc/inittab /etc/haha hi hello



2,自定义变量
(1) -v var=value
(2) 在program中直接定义









6. 输出命令
1,输出命令:print
用法:print item1,item2,...
item:字符串,用引号引用;
变量:显示变量的值,可以直接使用变量的名进行引用;
数值:不加引号

要点:
(1)各item之间使用逗号分隔;输出的分隔符默认为空白字符;
(2)输出的各item可以为字符串或数值、当前记录的字段($#)、变量或awk的表达式;数值会被饮食转换为字符串进行输出;
(3)print后的item省略时,相当于运行"print $0" ,
5b4
用于输出整行;

(4)输出空白字符:print " "
2,格式化输出:printf
用法:printf “FORMAT”, item1, item2, ...

(1)必须指定FORMAT;
(2) 不会自动换行,需要显式给出换行控制符,\n;
(3)FORMAT中需要分别为后面每个item指定格式符;
格式符:与item一一对应
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
&nb
7fe0
sp; %g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数

%%: 显示%自身
举例:

awk -F: '{printf "Username:%s UID:%s\n",$1,$3}' /etc/passwd



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



awk -F: 'BEGIN{printf "%.d %.2f\n",1.73333,3.1111}'



修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐) %-15s
+:显示数值的正负符号 %+d

7. awk操作符
1, 算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数

+x: 转换为数值
awk 'BEGIN{print 2^5}



2, 字符串操作符:没有符号的操作符,字符串连接
3, 赋值操作符:

=, +=,
-=, *=, /=, %=, ^=

++, --

awk 'BEGIN{print i++;print i}'
awk 'BEGIN{print ++i;print i}'



4, 比较操作符:

==, !=, >, >=, <, <=
awk -v FS=: '$3 == 0 {print $0}' /etc/passwd



5, 模式匹配符:

~:左边是否和右边匹配包含
!~:是否不匹配

awk '$0 ~ "^root" {print $0}' /etc/passwd



6, 逻辑操作符:与&&,或||,非!
awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd



7, 函数调用: function_name(argu1, argu2, ...)
8, 条件表达式(三目表达式):
selector?if-true-expression:if-false-expression
9,关系表达式
为非0时,即为真,才处理
为0或为空时,不处理
!0=1 !Num=0 (Num为任意非0的值)
举例:
df |awk -v FS=% '$0 ~ "/dev/sd" {print $1}'|awk '$NF>=10 {printf "DevName:%-10s Used:%s%%\n",$1,$5}'



8. PATTERN
PATTERN:根据pattern条件,过滤匹配的行,再做处理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来

awk '/^UUID/{print $1}' /etc/fstab
awk '!/^UUID/{print $1}' /etc/fstab



(3) relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
(4) 行范围:类似于vim sed 中的地址定界方式
cat /boot/grub/grub.conf |awk '/default/,/hidden/' 匹配以'/default/开始,以/hidden/结束'的范围



(5) BEGIN/END模式
BEGIN{ }:仅在开始处理文件中的文本之前执行一次
END{ }:仅在文本处理完成之后执行
9. 控制语句
1,if-else
语法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}
else{statement3}
使用场景:
对awk取得的整行或某个字段做条件判断
awk -v FS=: '{if($3>=1000){usertype="Common User"}else{usertype="Sys User"}printf "UserName:%-15s Type:%s\n",$1,usertype}' /etc/passwd



2,while循环
语法:
while(condition){statement;…}

条件“真”,进入循环;条件“假”,退出循环
使用场景:
对一行内的多个字段逐一类似处理时使用
对数组中的各元素逐一处理时使用
echo {1..10} |awk '{n=1;while(n<=NF){if($n%2==0){print $n,"oushuo"}eelse {print $n,"jishu"};n++}}'



3,do-while循环
语法:do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
4,for循环
语法:for(expr1;expr2;expr3) {statement;…}
常见用法:
for(variable assignment;condition;iteration process)
{for-body}
特殊用法:能够遍历数组中的元素
语法:for(var in array) {for-body}
5, switch语句

语法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
6, break和continue
break
:退出当前循环,n为数字,用于指定推出几层循环;
continue:提前结束本轮循环而进入下一轮;
awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i};print sum}'



awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==1)continue;sum+=i};print sum}'



7,next:提前结束对本行处理而直接进入下一行处理(awk自身循环)



awk -v FS=: '{if($3%2!=0) next;print $1,$3}' /etc/passwd



10. 数组
关联数组:array[index-expression]
index-expression:
(1) 可使用任意字符串;字符串要使用双引号括起来
(2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;要判断数组中是否存在某元素,要使用“index in array”格式进行遍历。
数组遍历:
若要遍历数组中的每个元素,要使用for循环
for(var in array) {for-body}
注意:
var会遍历array的每个索引



11. 函数
函数分为内建函数和用户自定义函数
1,内建函数
数值处理:rand():返回0至1之间的一个随机数;
awk 'BEGIN{srand();print int(rand()*10000)}'



字符串处理:
length([s]):返回指定的字符串的长度。
awk 'BEGIN{print length("hello")



sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s。
echo "2018:08:29 10:08:30" |awk 'sub(/:/,"-",$1)'



gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容。
echo "2018:08:08 08:08:08" |awk 'gsub(/:/,"-",$1)'  匹配第一字段
echo "2018:08:08 08:08:08" |awk 'gsub(/:/,"-",$0)'  匹配所有





split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中。
netstat -tan



netstat -tan |awk '/^tcp\>/&& !($5 ~ "*") {split($5,ip,":");count[ip[1]]++}ENcount[ip[1]]++}END{for(i in count){print i,count[i]}}'



注意:awk的数组下标从开始编号。
substr(s,i[,n]):从s所表示的字符串中取出字串。取法:从i表示的位置开始,取n个字符。

三、总结
记住三个命令的运用形式
grep '字符' 文件
sed '命令' 文件
awk '条件{命令}' 文件
单引号内就是正则表达式的用法
重复一遍:单引号内一定是正则表达式!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux awk 三剑客