awk简介


        awk同sed、grep被称为linux文本处理三剑客,都起源于行编辑器ed。awk继承了行编辑器的特点,循环的读取文本的每一行(或者是分隔符分割的每一段文本)直至文本结束,但是awk加入了段分割符的概念.将每次读入的行进行再次分割.awk每次读取的行都只是未经过awk语句处理的对象。或读取行后会根据段分割符在将行分成多个对象。结构近似数组,然后进行指定语句的操作。作为一款报表生成器,作用是对对文本内容进行各种排版,进而格式化显示。

       awk有自己的语法,可以说是一款独立的编程语言。 它对命令的处理可以称为命令的解释,或脚本语言的解释 awk的语句书写格式,属于模块化风格,特别是if,else语句表现的特别明显有点类似于bash中的匿名函数。每个语句块必须使用{}进行约束。

        本文介绍了awk的常用用法及讲解并添加示例以便加深理解,结尾准备了实战练习以加强巩固,请读者自行按需阅读,如有纰漏望请指出。

1、awk基本执行流程

2、awk基本格式

3、printf 用法及格式符、修饰符

4、awk中的控制语句

5、awk中的函数、变量及操作符

6、实战练习



1、awk基本执行流程

        ①执行BEGIN语句块中的内容,语句为可选语句.多用于执行变量的初始化,报表的头输出.

        ②从标准输入或文件中读取行分割符(-F定义的字符)分割的行进入内存,进行语句之前的条件匹配,在没有条件时默认为符合执行条件.符合条件执行,不符合条件则尝试匹配下一个语句之前的条件.直至所有条件匹配全部完成.当语句为空时默认执行{print $0}

         ③继续读取下一行,直至末尾

         ④执行END定义的语句内容,同样也为可选语句.多用于报表的统计信息输出.

2、awk基本格式及匹配条件

    基本格式: awk选项 条件 语句 文件

选项:

-f 从文件中读取处理命令
-F 指明行的段分隔符;默认为空白字符(一个或多个)
-v 自定义变量

条件

条件执行条件后的语句的要求。符合条件才可执行语句,条件即为对语句的判断,可以使用正则匹配,基于正则的模式定界,字符串比较,可以使用算数条件表达式也可以是BEGINEND特殊条件

算数条件表达式最终返回运算结果,当运算结果为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    打印效果相同。

3、printf 用法及格式符、修饰符

         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:    无符号的整数

修饰符

#[.#]:左边#用于显示宽度
       右边的#表示小数点后的精度 
- : 左对齐,默认右对齐。
+ :  显示数字的正负符号


4、awk中的控制语句

(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(i7){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被赋值的是每个索引

5、awk中的函数、变量及操作符

函数:分为内建函数和自定义函数

内建函数

数值处理: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脚本中用法不同

             && :并且

             || :或者

        !:非



6、awk实战练习

 (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