awk简介

Awk介绍

 

报告生成器,格式化文本输出

gawk:模式扫描和处理语言

基本用法:

Awk [option]  ‘program’ var=value file

Awk [ option]  -F    programfile var =value file   F指明分隔符

Awk [option ]   ‘BEGIN’{ACTION…}  pattern{action;…}   END{action;,,,}’   file,,,

Begin,没开始读,就开始做什么事,做表头

End,读完所有的行,干的事,统计平均成绩

工作原理:一行一行处理,自动读下一行,按定义的分隔符切割成字段,字段名,$1,$2,$3,,,对字段,轮流处理

基本格式

Awk  [option]    ‘program’     file

选项    awk自己的程序   要处理的文件

Program:   pattern{action statements;….}   满足pattern就执行action,不满足就跳到下一行

模式    动作指令

Pattern部分决定动作语句合适触发及触发事件

Begin    end

Action statements 对数据进行处理,放在{}内指明

Print打印必要的数据  printf详细的定义显示的格式,空格数,小数位

分隔符、域和记录

Awk执行时,由分隔符分隔的字段(域)标记$1,$2,,,,$n 称为域标识、$0为所有域,

文件的每一行称为记录,

省略action,则默认执行 print $0 的操作

 

Awk的工作原理

第一步:执行begin{action}语句块中的语句

第二步:从文件或标准输入(stdin)读取一行,然后执行pattern

{action,,}语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕

第三步:当读至输入流末尾时,执行END{action}语句块

Begin语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在begin语句块中

End语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在end语句块中完成,它也是一个可选语句块

Pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print}即打印每一个读取到的行,awk读取的每一行都会执行该语句块

Print格式:print item1,item2,,,,

要点:1逗号分隔符

2输出的各item可以是字符串,也可以是数值;当前记录的字段、变量或awk的表达式

3如省略item   相当于print$0

实例: awk -F: ‘{print $3}’ /etc/passwd    以:为分隔符 取第三列

df |grep /dev/sd |awk ‘{print $5}’ 以默认空白为分隔符,取第五列

 

Field,域,字段,列,column,属性

行,记录,record

 

Awk:内置和自定义变量

 

 

FS:输入字符分隔符,默认为空白字符

 

FS内置变量,使用时要写-v

 

 

Awk -v FS=:  {print $1,FS,$3} /etc/passwd

Awk -F:   {print $1,$3,$7} /etc/passwd

OFS:输出字段分隔符,默认为空白字符

输出的时候,定义为+为分隔符,OFS需要写-v,显示

 

 

 

Awk -v FS=’:’ -v OFS ’:’ ‘{print $1,$3,$7}’ /etc/passwd

RS:输入记录分隔符,指定输入时的换行符

输入记录换行符,默认为回车,

右图自定义为;碰见一个;就为一行

 

 

 

 

 

ORS:输出记录分隔符,输出时用指定符号代替换行符

定义—-为输出记录分隔符,即输出时—分隔一行

 

 

 

 

 

 

 

 

 

 

NF:字段数量 (NF本身就是一个变量,表示字段的数量) $NF 最后一个字段 $(NF-1)倒着数第一列

 

 

 

Ss -nt  ss命令用来显示处于活动状态的套接字信息

 

df命令参数功能:检查文件系统的磁盘空间占用情况

$(NF-1) 倒数第二个字段

 

Httpd的访问日志,取$1

 

 

 

 

NR:记录号

 

 

 

 

Awk  ‘{print NR}’  /etc/fstab

FNR:各文件分别计数,记录号

FILENAME:当前文件名

打印行号,空格也算一行,

FNR, 各文件独立编号   FILENAME:当前文件名

 

加文件名,各文件独立显示

 

ARGC:命令行参数的个数

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

 

命令行三个参数,’{}’是awk的程序

 

 

 

 

 

 

 

 

自定义变量(区分字符大小写)

 

 

 

 

可以在外面定义,也可以在里面定义

  • -v var =value
  • 在program中直接定义

-f  可以调用脚本

 

 

 

 

格式化输出Printf命令:  “FORMAT”, item1,item2,,,

  • 必须指定FORMAT
  • 不会自动换行,需要显示给出换行控制符,\n
  • FORMAT中需要分别为后面每个item指定格式符

格式符:与item一一对应

%c:显示字符的ASCII码

%d:%i:显示十进制整数

%e:%E:显示科学计数法数值

%显示为浮点数

%g,%G:以科学计数法或浮点形式显示数值

%s:显示字符串

%u:无符号整数

%%:显示%自身

修饰符:#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

– :左对齐(默认右对齐) %-15s

+ :显示数值的正负符号%+d

 

 

“”双引号里面的表示格式,%S $1按照字符串格式显示出来,默认不换行

%d $3 按照数字的格式显示出来              \n 表示换行

 

 

%-30s  表示的是字符左对齐,控制显示30字符,

%6d   表示的是数字右对齐,控制数字显示6字符

 

 

 

BEGIN在执行之前, 只是执行一次, 小数后面的位数溢出,自动四舍五入

 

 

 

例:

 

 

当读入一行,由于pattern没有定义,所以这个行就符合条件,符合条件,就执行action,就是打印,即print,hello.awk 执行结果和etc/fstab无关,只是这个文件有几行,就打印几次hello.awk

可以管道,cat /etc/fstab | awk ‘{print “hello,awk”}’

可以重定向,awk   ’{print “hello,awk”}’  < /etc/fstab

支持/n换行   awk ‘{print “hello,awk\nhello.27class”}’ /etc/fstab

支持运算     awk ‘{print 2*3}’ /etc/fstab

 

 

 

可以用cut -d: -f3 /etc/passwd

awk -F: ‘{print $1,$3,$7}’ /app/passwd  -F:分隔符为:没有写pattern,就是每一条都符合,按:来取,$3,就是取第三行uid,

 

 

Awk 默认的分隔符为 空白符

取分区利用率,$5第五行 ,

$1 $5 之间用逗号隔开,输出为空格,也可以在括号内用“ ”使用空格,$1时变量不能使用“”,“”表示使用的是字符串  “\t”“\n”也可以

 

 

$0表示打印整行,什么也不写默认打印$0

 

操作符

算数操作符

X+y,x-y,x*y, x/y,x^y,   x%y

-x:转换为负数

+y:转换为正数

字符操作符:没有符号的操作符,字符串连接

赋值操作符

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

++,–

[root@Centos6 ~]# awk ‘BEGIN{i=0;print ++i,i}’ 先做运算,在打印出来

1 1

[root@Centos6 ~]# awk ‘BEGIN{i=0;print i++,i}’先赋值,在进行加运算

0 1

比较操作符

==,  !=  >,  >=,   <    <=

模式匹配符:

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

实例

[root@Centos6 ~]# awk ‘$0 ~ “^wang”‘ /etc/passwd

wang:x:500:500::/home/wang:/bin/bash

[root@Centos6 ~]# awk ‘$0 ~ “^root”‘ /etc/passwd

root:x:0:0:root:/root:/bin/bash

表示以wang开头的,^表示行首,,,省略{print}表示打印全行

 [root@Centos6 ~]# awk ‘$0 ~ /^root/’ /etc/passwd

root:x:0:0:root:/root:/bin/bash

“” / /  都可以表示中间的是正则表达式,效果一样

[root@Centos6 ~]# awk ‘$0 ~ /^(root|wang)/’ /etc/passwd

root:x:0:0:root:/root:/bin/bash

wang:x:500:500::/home/wang:/bin/bash

支持扩展的正则表达式,使用””是一样可以使用扩展正则表达式

 

[root@Centos6 ~]# awk -F: ‘$3==0’ /etc/passwd

root:x:0:0:root:/root:/bin/bash

[root@Centos6 ~]# awk -F: ‘$3>=1000’ /etc/passwd

nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin

模式匹配,相当于”$3==0{print$0}”

变量的值,0,空字符,没定义,都当假 (在awk中0表示假,1表示真)

只要是有值,都认为为真

awk  -v  i=0  ‘i’  /etc/issue    相当于awk -v i=0 i{print $0}

awk  -v  i=   ‘i’  /etc/issue

awk  -v  i=”” ‘i’  /etc/issue

逻辑操作符:与&&,或||,非!

示例

[root@Centos6 ~]# awk -F: ‘ $3 >=0 && $3<=1000 {print $1}’ /etc/passwd

[root@Centos6 ~]# awk -F: ‘ $NF ==”/bin/bash” {print $1,$NF}’ /etc/passwd

root /bin/bash

wang /bin/bash

haha /bin/bash

hehe /bin/bash

[root@Centos6 ~]# awk -F: ‘!($3==0){print $1}’ /etc/passwd

匹配不是root的其他账号

!i++  先做取反,在赋值计算,++i 先赋值计算,在取反

条件表达式(三目表达式)

—?—:—

awk -F: ‘{$3>=1000?usertype=”common user”:usertype=”sysuser”;printf “%-30s:%-30s %15d  \n”,usertype,$1,$3″}’ /etc/passwd

PATTERN:根据pattern条件,过滤匹配的行,在做处理

  • 如果未指定:空模式,匹配每一行
  • /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
  • Relational expression:关系表达式,结果为真,才会被处理
  • 真:结果为非0值,非空字符串

假:结果为空字符串或0值

[root@Centos6 ~]# awk -F: ‘/^[^#]/{print $1}’ /etc/profile

[root@Centos6 ~]grep  ‘^[^#]’   /etc/profile

 

awk -F: ‘!/^UUID/{print $1}’ /etc/fstab

awk -F: ‘/^UUID/{print $1}’ /etc/fstab

显示,非#开头的行

 

Seq 10

Seq 10 |sed -n  1-2p  打印奇数行

Seq 10 |sed -n  2-2p  打印偶数行

[root@Centos6 ~]# seq 10 |awk ‘!(i=!i)’

2

4

6

8

10

[root@Centos6 ~]# seq 10 |awk -v i=2 ‘(i=!i)’ 开始i=2,!i=0,不打印,第二次,i=0;!i=1,打印该行

2

4

6

8

10

[root@Centos6 ~]# seq 10 |awk ‘i=!i’  开始i为空,!i=1,则打印改行,第二次,i=1;!i=0,则不打印该行

1

3

5

7

9

  • line ranges 行范围

Startline,endline:/part1/,/part2/不支持直接给出数字格式

 

 

 

打印第二行到第五行

 

 

BEGIN和END模式

BEGIN{}:仅在开始处理文件中的文本之前执行一次

END{}:仅在文本处理完成之后执行一次

常用的action分类

1,算数,比较表达式

2,if,while 语句

3,组合语句

4,input statements

5,output statements:print等

Awk控制语句

{statements;…}组合语句

If(condition){statements,…}

If(condition){station;…}else{stations;…}

While(conditon){stations;…}

Do{stations;…}while(condition)

For(expr1;expr2;expr3){stations;…}

Break

Continue

Delete array[index]

Delete array

Exit

[root@Centos6 ~]# df |awk ‘{if($0 ~ /\/dev\/sd/)print $1,$5}’

/dev/sda3 8%

/dev/sda2 1%

/dev/sda1 4%

[root@Centos6 ~]# df |awk ‘/^\/dev\/sd/{print $1,$5}’

/dev/sda3 8%

/dev/sda2 1%

/dev/sda1 4%

如果分区的利用率大于80,就把分区的名称显示出来

[root@Centos6 ~]# df | awk -F% ‘/^\/dev\/sd/{print $(NF-1)}’

/dev/sda3       50264772 3582396  44122376   8

/dev/sda2       60344404   57644  57214760   1

/dev/sda1         999320   34952    911940   4

[root@Centos6 ~]# df | awk -F% ‘/^\/dev\/sd/{print $(NF-1)}’|awk ‘{if($5>4)print $1,$5}’

/dev/sda3 8

 

 

[root@Centos6 ~]# df | awk -F “[ %]+” ‘/^\/dev\/sd/{if($(NF-2)>4)print $1,$5}’

/dev/sda3 8

/dev/sda2 1

/dev/sda1 4

[root@Centos6 ~]# df | awk -F “[ %]*” ‘/^\/dev\/sd/{if($(NF-2)>4)print $1,$5}’

/dev/sda3 8

/dev/sda2 1

/dev/sda1 4

表示以空格和%同时为分隔符

 

[root@Centos6 ~]# awk -F: ‘{print $1,length($1)}’ /etc/passwd

root 4

bin 3

daemon 6

统计字符串的长度

[root@Centos6 ~]# awk -F: ‘/^root/{i=1;while(i<=NF){print $i,length($i);i++}}’ /etc/passwd

root 4

x 1

0 1

0 1

root 4

/root 5

/bin/bash 9

统计root行,各字符串的长度

[root@Centos6 ~]# awk -F: ‘BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++}print sum}’

5050

[root@Centos6 ~]# awk -F: ‘BEGIN{i=1;sum=0;do{sum+=i;i++}while(i<=100);print sum}’

5050

[root@Centos6 ~]# seq -s+ 1 100

1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100

[root@Centos6 ~]# seq -s+ 1 100|bc

5050

 

While循环

语法:while(condition){statements;…}

条件“真”,进入循环;条件“假”,退出循环

使用场景:

对一行内的多个字段逐一类处理时使用

对数组中的各元素逐一处理时使用

示例

Do-while循环

语法:do{statement;…}while(condition)

意义:无论真假,至少执行一次循环体

For循环

语法:for(expr1;expr2;expr3){statements;….}

常见用法

特殊用法:能够遍历数组中的元素

语法for(var in array){for-body}

 

性能比较

 

time for((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum

[root@Centos6 ~]# time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)

[root@Centos6 ~]# time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)

[root@Centos6 ~]# time(sep -s “+” 10000|bc)

 

 

Switch语句

语法:switch(expression){case VALUE1 or /regexp/:statement1;case VALUE2 or /regexp2/:statement2;…default:statement}

 

Break和continue

[root@Centos6 ~]# awk -F: ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2!=0)continue;sum+=i}print sum}’

2550

[root@Centos6 ~]# awk -F: ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==10)break;sum+=i}print sum}’

45

 

Next:

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

[root@Centos6 ~]# awk -F: ‘{if($3%2!=0)next; print $1,$3}’ /etc/passwd

root 0

daemon 2

lp 4

只执行偶数行的循环,满足条件即不是偶数行next,跳过 不执行

 

Awk数组

关联数组:array[index-expression]

Index-expression

1,可使用任意字符串;字符串要是用双括号括起来

2,如果某数组元素实现不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

示例

f1 aa bbb ccc aaaa bbbb ccc aa bbb

awk ‘!arr[$0]++’ f1

开始aa读进来,[“aa”]没有定义  arr[“aa”]没有值,!arr[$0]就为真,执行print;经过这次之后进行++,arr[aa]=1

同样的道理,arr[“bbb”]没有赋值,取反之后,!arr[“bbb”]为真,进行打印,打印之后进行++,arr[bbb]=1

………第二次遇到ccc,就不打印了,,,执行结果就是去掉重复行

Sort f1|uniq   sort先排序,排序后

 

加加和赋值没有关系,先赋值,在进行加加

第一行读进来,没有定义,

Arr[aa]为空,取反!arr[aa]的结果为1,

再进行加加,加加之后,数组arr[“aa”]=1

第二次,碰到aa,arr[“aa”]=1,!arr[“aa”]=0

再进行加加,数组arr[“aa”]=2

 

 

 

 

 

Awk ‘arr[$0]++;’ dupfile

把一个文件中的多余行去掉

 

 

 

 

Awk数组

若要遍历数组中的每一个元素,要使用for循环

For(var in array){for-body}

注意:var会遍历array中的每一个索引

 

Netstat -nat 显示网路连接状态

[root@centos7 ~]# netstat -nat

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State

tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN

tcp        0     52 192.168.27.8:22         192.168.27.1:51066      ESTABLISHED

tcp6       0      0 :::111                  :::*                    LISTEN

 

[root@centos7 ~]# netstat -tan |awk ‘/^tcp/{state[$NF]++ }END{for(i in state){print i,state[i]}}’

LISTEN 9

ESTABLISHED 1

一行一行处理,

过滤以tcp开头的,数组的下标为$NF,最后一个变量的值当成下标,每读出来一个值,就加一次

统计完之后,用end,for循环,把状态遍历出来

前面一个{}把各状态次数,相加起来,统计的结果就是放在state[]当中

 

处理日志

统计每个ip访问了多少次

 

 

 

 

 

 

当访问次数超过1000次放到防火墙中

 

 

 

 

 

 

 

 

 

 

 

–j<目标>:指定要跳转的目标;

A:向规则链中添加条目;

-s:指定要匹配的数据包源ip地址;

INPUT链:处理输入数据包

 

 

 

 

并发连接数(正在连接的数目)达到一个数,就把他放到防火墙里,

[root@centos7 ~]# ss -nt|awk -F “[ :]+” ‘/ESTAB/{print $(NF-2)}’|sort |uniq -c

1 192.168.27.1

[root@centos7 ~]# ss -nt|awk -F “[ :]+” ‘/ESTAB/{ip[$(NF-2)]++}END{for(i in ip){print i,ip[i]}}’

192.168.27.1 1

并发连接数前三个面试题

 

Linux sort命令用于将文本文件内容加以排序

-r 以相反的顺序来排序

-n 依照数值的大小排序。

Linux uniq命令用于检查及删除文本文件中重复出现的行列

-c或–count 在每列旁边显示该行重复出现的次数

数值处理

 

字符串处理

Rand()返回0和1之间的一个随机数

awk ‘BEGIN{srand();for(i=0;i<10;i++)print int(rand()*100) }’

 

Length([s])返回指定字符串的长度

Sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

[root@centos7 ~]# echo “2008:08:08 08:08:08″| awk ‘sub(/:/,”-“,$1)’

2008-08:08 08:08:08

Sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将全部匹配的内容替换为s

[root@centos7 ~]# echo “2008:08:08 08:08:08″| awk ‘gsub(/:/,”-“,$1)’

2008-08-08 08:08:08

Split(s,array,[t]);以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第一个索引值为1,第二个索引值为2

 

[root@centos7 ~]# netstat -tan |awk ‘/^tcp\>/{split($5,ip,”:”);count[ip[1]]++}END{for(i in count){print i,count[i]}}’

0.0.0.0 5

192.168.27.1 1

^行首牟定,\>词尾牟定(例如tcp6就不符合),$5远程主机的IP及端口号,用:做分隔符切割,第五列,放到ip数组中 Ip[1]中存放的是ip地址,count[ip[1]]++ 同一个ip地址放到数组count中,计算数量,结束之后对count做遍历,打印i,i为count的下标,即ip地址,而count[i]就是对应的ip的数量

[root@centos7 ~]# awk ‘{for(i=1;i<=NF;i++)word[$i]++}END{for(i in word)print i,word[i]}’ /etc/profile

统计每个单词的数量       每一行读进来之后,每个单词作为word的下标,下标一样加加,不一样形成新的数组

默认以空格作为分隔符, 最后,进行统计,

 

[root@centos7~]# awk ‘{if($3==”male”){mnum++;msum+=$2}else{fnum++;fsum+=$2}}

END{printf “male:%d %.2f\nfemale:%d %.2f”,mnum,msum/mnum,fnum,fsum/fnum}’ f1

male:2 95.00

female:2 92.00

[root@centos7 ~]# awk ‘{num[$3]++;sum[$3]+=$2}END{for(sex in num){print sex,num[sex],sum[sex]/num[sex]}}’ f1

female 2 92

male 2 95

[root@centos7 ~]# vim f1

mage  100   male

wang   90   male

zhang  85   female

mo     99   female

 

使用数组,num[$3]人的个数,使用$3作为它的下标,表现为,num[“male”]   num[“female”]

num[$3]++表示为male和female人数总和

num[$3]+=$2  同一个性别的下标,把成绩往相同的下标里累加,最后统计就可以,遍历

 

Awk自定义函数

[root@centos7 ~]# awk -f f1.awk

3

[root@centos7 ~]# vim f1.awk

function max(v1,v2){

v1>v2?var=v1:var=v2

return var

}

BEGIN{a=3;b=2;print max(a,b)}

调用awk函数

 

 

调用awk脚本

Awk中调用shell中的命令

[root@centos7 ~]# awk ‘BEGIN{system(“hostname“)}’

centos7.magedu.com

[root@centos7 ~]# awk ‘BEGIN{system(“uname -r“)}’

3.10.0-693.el7.x86_64

[root@centos7 ~]# awk ‘BEGIN{name=”mage”;system(“echo “name)}’

mage    echo后面有空格

连接数大于3的禁用

ss -nt |awk -F “[ :]+” ‘/^ESTAB/{IP[$(NF-2)]++}END{for(i in IP){if(IP[i] >3)system(“iptables -A INPUT -s “i” -j REJECT”)}}’

向awk脚本传递参数

格式:

Awkfile var=value  var2=value2…inputfile

注意:在BEGIN过程中不可用、直到首行输入完成以后,变量才可用。可以通过-v参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变量都需要一个-v参数

 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/90785

联系我们

400-080-6560

在线咨询

工作时间:周一至周五,9:30-18:30,节假日同时也值班

QR code