awk简介
awk同sed、grep被称为linux文本处理三剑客,都起源于行编辑器ed。awk继承了行编辑器的特点,循环的读取文本的每一行(或者是分隔符分割的每一段文本)直至文本结束,但是awk加入了段分割符的概念.将每次读入的行进行再次分割.awk每次读取的行都只是未经过awk语句处理的对象。或读取行后会根据段分割符在将行分成多个对象。结构近似数组,然后进行指定语句的操作。作为一款报表生成器,作用是对对文本内容进行各种排版,进而格式化显示。
awk有自己的语法,可以说是一款独立的编程语言。 它对命令的处理可以称为命令的解释,或脚本语言的解释 awk的语句书写格式,属于模块化风格,特别是if,else语句表现的特别明显有点类似于bash中的匿名函数。每个语句块必须使用{}进行约束。
本文介绍了awk的常用用法及讲解并添加示例以便加深理解,结尾准备了实战练习以加强巩固,请读者自行按需阅读,如有纰漏望请指出。
1、awk基本执行流程
1、awk基本执行流程
①执行BEGIN语句块中的内容,语句为可选语句.多用于执行变量的初始化,报表的头输出.
②从标准输入或文件中读取行分割符(-F定义的字符)分割的行进入内存,进行语句之前的条件匹配,在没有条件时默认为符合执行条件.符合条件执行,不符合条件则尝试匹配下一个语句之前的条件.直至所有条件匹配全部完成.当语句为空时默认执行{print $0}
③继续读取下一行,直至末尾
④执行END定义的语句内容,同样也为可选语句.多用于报表的统计信息输出.
基本格式: awk选项 条件 语句 文件
选项:
-f 从文件中读取处理命令 -F 指明行的段分隔符;默认为空白字符(一个或多个) -v 自定义变量
条件:
条件为执行条件后的语句的要求。符合条件才可执行语句,条件即为对语句的判断,可以使用正则匹配,基于正则的模式定界,字符串比较,可以使用算数条件表达式,也可以是BEGIN,END特殊条件。
算数条件表达式,最终返回运算结果,当运算结果为0时,语句不执行。当语句为空时,默认执行{print $0}。
例:正则_匹配正则匹配的每一行
awk '/^UUID/{print $1}'/etc/fstab 匹配以UUID为开始的行,并执行{}中的语句。print $1 awk '!/^UUID/{print $1}' /etc/fstab 匹配以非UUID为开始的行,执行{}中的语句 。print $1
例:算数计算_条件为真该行才会被处理 ,条件 为假则不处理 。
awk -F: '$3>=1000{print $1,$3}' /etc/passwd awk -F:'(NR>=2&&NR<=10){print $1}'
例:字符串比较_比较结果为真进入循环
awk -F:'$NF="/bin/bash"{print $1,$NF}' /etc/passwd awk -F:'$NF~"bash$"{print $1,$NF}' /etc/passwd awk -F: '! ($NF=="/bin/bash")' /etc/passwd
例:行范围_范围内的行做处理 ,只支持模式定界(类似sed中的10,20地址定界不支持)
awk -F:'/^root/,/^myuser/{print $1}'
例:特殊条件_BEGIN/END
BEGIN:在开始之前显示一次 END:在文本处理完成 ,命令未完成时,执行一次 awk -F: 'BEGIN{print "name\n-----------"}{printf "%-10s\n",$1}END{print "=========="}' /etc/passwd
awk -v aa="" 'aa' /etc/passwd 变量aa的值为空 ,(语句为空执行默认语句)。但是条件为空,不执行默认语句。 awk -v aa=" " 'aa' /etc/passwd 变量aa的值为‘ ’空格不为空执行默认语句 awk -v aa="0" 'aa' /etc/passwd 变量aa的值为0,条件为最终值为0,默认语句不执行。 awk ‘!arr[$0]++’ dupfile 以$0为下标建立数组,只打印文件不重复的行 awk -v aa=0 'aa++' /etc/passwd aa初始值为0,第一条语句条件为a++,首先返回a的值在进行自加运算。所以打印第一行外所有行。awk中 默认对非关键字变量都赋值0,这个例子也可以写成 awk 'aa++' /etc/passwd 打印效果相同。
print类似bash中的echo打印给定字符并自动添加换行这里不多说,printf对输出格式可以自定义,用法需要大家注意。
语法:printf FORMAT,item1,item2,...
①必须提供FORMAT
②printf不会自动换行,若想换行需加换行符:\n
③FORMAT中需要依次分别为后面每一个item指定一个格式符,否则item不显示。
格式符:
%c : 显示字符的ascii码 %d或i: 显示十进制整数 %e或%E:科学记数法显示数值 %f: 显示浮点数 %s: 显示字符串 %% : 显示%自身 %g或%G:以科学计算法或浮点数格式显示数值 %u: 无符号的整数
修饰符:
#[.#]:左边#用于显示宽度 右边的#表示小数点后的精度 - : 左对齐,默认右对齐。 + : 显示数字的正负符号
(1)、条件表达式
格式:条件?条件为真的语句:条件为假的语句
例:
awk -F:‘{$3>=500?usertype="common":usertype="sysadmin";printf "%15s:%-s\n",$1,usertype}’ /etc/passwd
(2)、if-else:
格式:
if(条件){语句} if(条件){语句} else {语句}
例:
awk -F: '{if($3>1000) print $1,$3}' /etc/passwd awk -F: '{if($3>1000){printf "普通用户:%s\n",$1} else {printf "系统用户:%s\n",$1}}' /etc/passwd
(3)、while循环:
while (条件) {语句} 条件为真进入循环 ,条件为假退出循环。
例:
awk '/^[[:space:]]*linux/{i=1;while(i<NF){print $i,length($i);i++}}' /etc/grub2.cfg awk '/^[[:space:]]*linux/{i=1;while(i<NF){if(length($i)>7){print $i,length($i)};i++}}' /etc/grub2.cfg
(4)、do-while循环:
do{语句} while(条件)
首先执行do后面的语句。然后对while中的条件进行判断。条件符合继续执行do后的语句。至少执行一次循环。
(5)、for循环:
语法:for(expr1;expr2;expr3){statements}
例:
awk /[[:space:]]*linux/{for(i=1;i<=NF;i++){print $i,length($i)}} /etc/grub2.cfg
for可以实现遍历数组元素 :
格式 :for (i in 数组名称)遍历时 i被赋值的是每个索引
函数:分为内建函数和自定义函数
内建函数:
数值处理:rand()与srand() 组合使用返回一个0至1之间的随机数。
字符串处理:
①length([s]):统计指定字符串的长度,并返回。
②sub(r,s[,t]):处理字符串t(可以是单纯的字符串,变量,位置引用),对t进行模式匹配,模式定义在r中,将模式r所匹配的内容替换成s中的内容,但是只进行1次替换
例:echo "2008:08:08:08 08:08:08:08" |awk 'sub(":","-")'
③gsub (r,s,[t]):处理字符串t(可以是单纯的字符串,变量,位置引用),对t进行模式匹配,模式定义在r中,将模式r所匹配的内容替换成s中的内容,对于待处理的字符串t进行全局替换。
例:echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub("[^0-9]","")'
④split(a,array,[r]):以r为分隔符,分割字符串a,并将分割后的字符串分别存入数组,数组的下标从1开始,第一个索引为1,第二个索引为2.
例:netstat -tan |awk '/^tcp/{split($4,ip,":");a[ip[1]]++}END{for(i in a){print i,a[ip[1]]}}'
⑤int:将指定的内容转换为整数类型
自定义函数
格式:
function 函数名称 (参数1 ,参数2 。。。){ 语句1 语句2 return 数值 }
例:
#cat fun.awk function max(v1,v2) { v1>v2?var=v1:var=v2 return var } BEGIN{a=3;b=2;print max(a,b)}
变量:分为内建变量和自定义变量
内建变量:
FS:输入的字段分割符,默认为空白字符
OFS:输出的字段分隔符,默认也为空白字符。
RS:输入时指明的行分割符,默认就是换行符,
ORS:输出时的行分隔符,默认为换行符
NF :行中的字段数量
NR :行计数器 ,如果跟了多个文件编号会连续
FNR : 行数,各文件单独计数 。
FILENAME : 当前的文件名
ARGC :命令行中的参数个数(awk也算一个参数)
ARGV :命令行中的参数 ,ARGV为数组,参数为命令自身及后跟随的文件 ,语句不计入参数
自定义的变量
-v var=value
在语句中直接定义,多条与语句之间使用 ;分隔,每定义一个变量需要一个-v。
操作符
算数操作符 :实现算数运算x+y x-y x*y x/y x^y x%y
-x :将x 转化为负数
+x :将字符串x 转化为 数值
赋值操作符 :通常为变量赋值
= += -= *= /= ^= %=
++ --
比较操作符:> >= < <= != ==
模式匹配操作符:根据右侧的模式进行匹配操作
~ : 是否由右侧模式匹配
!~:是否由右侧模式不匹配
逻辑操作符 :进行逻辑的运算与bash脚本中用法不同
&& :并且
|| :或者
!:非
(1)、统计/etc/fstab文件中每个文件系统类型出现的次数
awk '!/^#/{arr[$3]++}END{for(i in arr){print i,arr[i]}}' /etc/fstab
(2)、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中的所有数字
echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw"|awk 'gsub(/[^0-9]/,"",$0)'
(3)、统计/etc/fstab文件中每个单词出现的次数
awk '{i=1;while(i<=NF){word[$i]++;i++}}END{for(num in word){print num,word[num]}}' /etc/fstab
(4)、计算男生女生的总成绩,平均成绩
#cat 1.txt mage 100 male wang 80 male zhang 70 female li 100 female #awk '{if($3=="male"){msum+=$2;mnum++}else{fesum+=$2;fenum++}}END{printf "%-5d %-.2f\n%-5d %-.2f\n",msum,msum/mnum,fesum,fesum/fenum}' 1
转载于:https://blog.51cto.com/arm2012/1963105