1 简介

awk:报告生成器,主要用于将文本格式化输出,同时也是一门独立的编程语言,awk这个名称是由该命令工具的三个创始人名字首字母缩写组成,分别是Aho,Weinberger和Kernighan;在 20 世纪 80 年代中期的时候,三个开发者对awk语言进行了更新,并称为nawk(new awk) ,该版本可以说是原来的增强版。
gawk:及GNU awk的缩写,由于受unix版权的影响,GUN组织后来就对awk进行了重写,通常我们工作中常用的Linux发行版都是gawk,虽说我们命令还是用的awk,其只是对gawk做了一个软链接。
image.png

2 基本用法

语法格式:
]# awk [options] ‘program’ FILE ….
选项:
-F 指明输入时用到的字段分隔符;
-v var=value:自定义变量;
program:PATTERT{ACTION STATEMENTS},语句之间用分号分隔,常用的ACTION如print和printf等

2.1 变量

2.1.1 内置变量

FS:input fileld seperator,默认为空白字符;
OFS:output field seperator,默认为空白字符;
RS:input record seperator,输入时的换行符;
ORS:output record seperator,输出时的
NF:number of field,字段数量,{print NF},{print $NF} awk引用变量无需$
NR:文件行数
FNR:各文件分别计数,行数;
FILENAME: 当前文件名;
ARGC:命令行参数个数;
ARGV:数组,保存的是命令行所给定的各参数
示例
1、对/etc/passwd文件中用户名和id进行显示,以”:”为分隔符,显示时也以”:”为分隔符
~]# awk -v FS=’:’ -v OFS=’:’ ‘{print $1,$3}’ /etc/passwd
image.png
2、以”:”为分隔符,显示最后一个字段
image.png

2.1.2 自定义变量

自定义变量有两种定义方式:
1、-v var=value,变量名区分大小写;
2、在program中直接定义
示例:
image.png

2.2 操作符

因为awk也是一种编程语言,因此也支持如其他编程一样的各种操作符
1、算数运算操作符:
x+y,x-y,xy,x/y,x^y,x%y
-x
+x:转换为数值;
2、字符串操作符:没有符号的操作符,字符串连接
3、赋值操作符:
=,+=,-=,
=,/=,%=,^=
++,—
4、比较操作符:
>,>=,<,<=,!=,==
5、模式匹配符:
~:是否匹配
!~:是否不匹配
6、逻辑操作符:
&&
||
!
7、函数调用:
function_name(argu1,argu2,….)
8、条件表达式:
selector?if-true-expression:if-false-expressionz
~]# awk -F: ‘{$3>=1000?usertype=”Com User”:usertype=”Sysuser”;printf “%-15s:%s\n”,$1,usertype}’ /etc/passwd
image.png

2.3 pattern模式匹配

该pattern表示只有被该模式所匹配到的行才会执行后面program的动作
1)empty:空模式,匹配每一行;
2)/regular expression/:仅处理能够被此处的模式匹配到的行
3)relational expression:关系表达式,结果有真有假,结果为真才被处理,结果为假忽略;
真:表示结果为非0值,非空字符串;
示例:对id大于1000的行才进行处理显示
~]# awk -F: ‘$3>=1000{print $1,$3}’ /etc/passwd
4)line ranges:行范围
startline,endline:/pat1,/pat2/,注意:不支持直接给出数字的格式
~]# awk -F: ‘(NR>=2&&NR<=10){print $1}’ /etc/fstab
5)BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次;
END{}:仅在文本处理完成之后执行一次;
~]# awk -F: ‘BEGIN{print “—-username—-uid—-“}{print $1,$3}END{print”—-结束了—-\n”}’ /etc/passwd

2.4 常用action

1)Expressions
2)Control statements:if,while等;
3)Compound statements:组合语句;
4)input statements
5)output statements

2.4.1 print

print item1, item2, item3, ……
要点:
1)逗号分隔符;
2)输出的各item可以是字符串,也可以是数值;当前记录的字段,变量或awk的表达式;
3)如省略item,相当于print $0;

2.4.2 printf

格式化输出:printf FORMAT,item1,item2,……
1)FORMAT是必须给出;
2)不会自动换行,需要显式给出换行符,\n
3)FORMAT中需要分别为后面的每个item指定一个格式化符号;
格式符:
%c:显示字符的ASCII码
%d,%i:显示十进制整数;
%e,%E:科学计数法数值显示;
%f:显示为浮点数;
%g,%G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%:显示%自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;
%3.1f
-:左对齐,默认右对齐
+:显示数值的符号
~]# awk -F: ‘{printf “Username: %-20s UID:%d\n”,$1,$3}’ /etc/passwd
image.png

2.4.3 控制语句

if(condition) {statements}
if(condition){statements} else {statements}
while(condition){statements}
do {statements} while(condition)
for(expr1;expr2;expr3){statements}
break
continue
delete array[index]
delete array
exit
{statements}
1)if-else
语法:if(condition) statement [else statement]
~]# awk -F: ‘{if($3>=1000) print $1,$3}’ /etc/passwd
~]# awk -F: ‘{if($3>=1000) {printf “Com user:%s\n”,$1} else {printf “Sysuser:%s\n”,$1}}’ /etc/passwd
~]# awk -F: ‘{if($NF==”/bin/bash”) print $1}’ /etc/passwd
~]# awk ‘{if(NF>5) print $0}’ /etc/fstab
使用场景:对awk取得的整行或某个字段做条件判断;
2)while循环
语法:while(condition) statement,条件”真”,进入循环;条件”假”,推出循环;
使用场景:对一行内的多个字段逐一类似处理时使用,对数组中的各元素逐一处理时使用;
~]# awk ‘/^[[:space:]]linux16/{i=1;while(i<=NF){print $i,length($i);i++}}’ /etc/grub2.cfg
~]# awk ‘/^[[:space:]]
linux16/{i=1;while(i<=NF){if(length($i)>=7){print $i,length($i)};i++}}’ /etc/grub2.cfg
3)do-while循环
语法:do statement while(condition),至少执行一次循环
4)for循环
语法: for(expr1;expr2;expr3) statement
~]# awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}’ /etc/grub2.cfg
特殊用法:能够遍历数组中的元素;
语法:for (var in array){for-body}
5)switch语法,多分枝
语法:switch(expression ){case VALUE1 or /REGEXP/: statement;case VALUE2 or /REGEXP2/: statement;…;default:statement}
6)break和continue
break [n]
continue
7)next
控制awk的内生循环
~]# awk -F: ‘{if($3%2!=0) next;print $1,$3}’ /etc/passwd

2.4.4 array

关联数组:array[index-expression]
index-expression:
1)可使用任意字符串,字符串要使用双引号;
2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为空串;
若要按段数组中是否存在某元素,要使用”index in array”格式进行;
weekdays[mon]=”Monday”
~]# awk ‘BEGIN{weekdays[“mon”]=”Monday”;weekdays[“tue”]=”Tuesday”;for(i in weekdays) {print weekdays[i]}}’
注意:var会遍历array的每个索引;
~]# netstat -tan | awk ‘/^tcp>/{state[$NF]++}END{for( i in state){print i,state[i]}}’
练习:统计/etc/fstab文件中每个文件系统类型出现的次数;
[root@kafka-01 ~]# awk ‘/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}’ /etc/fstab
练习:统计指定文件中每个单词出现的次数;
[root@kafka-01 ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}’ /etc/fstab

2.4.5 函数

2.4.5.1 内置函数

数值处理:
rand(): 返回0和1之间的一个随机数;
字符串处理:
length([s]): 返回指定字符串的长度;
sub(r,s,[t]): 以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替换为s
gsub(r,s,[t]): 以r表示的模式来查找t所表示的字符串中匹配的内容,并将其所有出现均替换为s所表示的内容;
split(s,a[,r]): 以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
示例:
~]# netstat -tan | awk ‘/^tcp>/{split($5,ip,”:”);count[ip[1]]++}END{for(i in count) {print i,count[i]}}’
将awk变量传递给shell,以便其他命令调用
~]# eval $(awk -F: ‘{printf(“pdn=%s;ns=%s;”,$1,$3)}’ /etc/passwd)
统计access.log下IP访问次数
~]# awk ‘{ip[$1]++}END{for( i in ip){print i,ip[i]}}’ /var/log/nginx/access.log
重启所有pod
~]# kubectl get pod -A | awk ‘{system(“kubectl delete pod “ $2 “ -n “ $1)}’

2.4.5.2 自定义函数

比较少使用,这里不做说明