awk学习笔记之实用案例

案例1:插入几个新字段
在”a b c d”的b后面插入3个字段e f g
思路:在b后面插入e f g相当于在c前面插入e f g
在这里插入图片描述
Note:修改字段(会反馈给$0,相当于修改了$0)或者修改$0后会重建$0(根据OFS重建$0),OFS的默认值是一个空格。

案列2:格式化空白
移除每行的前缀、后缀、空白,并将各部分左对齐
原始文档格式
在这里插入图片描述
直接给字段赋原值就可以格式化文本,因为更改字段会以OFS重建$0

在这里插入图片描述
上面的方法是以单个空格隔开每个字段,但是我们想用制表符隔开每个字段的话,因该如下操作
在这里插入图片描述
案列3:筛选IPv4地址
从ifconfig命令的结果中筛选出除了lo网卡外的所有IPv4地址
方法1:

#ifconfig | awk '/inet / && !($2 ~ /^127/){print $2}'

在这里插入图片描述
方法2:
按段落读取,默认情况下awk是以行读取,所以需要修改输入分割控制符(RS)
RS="":按段落读取
RS="\0":一次性读取所有数据,但有些特殊文件中包含了空字符\0
RS="^$":真正的一次性读取所有数据,因为非空文件不可能匹配成功
RS="\n+":按行读取,但忽略所有空行

#ifconfig | awk 'BEGIN{RS=""}{print}'

在这里插入图片描述
只输出第一段落

#ifconfig |awk 'BEGIN{RS=""}NR==1{print}'

在这里插入图片描述
取得ip地址,需要知道其在第几个字段,字段默认是以空格划分的,所以数一下ip在第几个字段,注意换行符也是空格,所以ip在地6个字段

#ifconfig |awk 'BEGIN{RS=""}NR==1{print $6}'

在这里插入图片描述
但是以上取法不是很好,会受到网卡的排列顺序影响,进一步改进,将lo开头的网卡排除在外即可

#ifconfig |awk 'BEGIN{RS=""}!/^lo:/{print $6}'

在这里插入图片描述
方法3:
取出段后再按行划分字段(以换行符划分)

#ifconfig |awk 'BEGIN{RS="";FS="\n"}!/^lo:/{$0=$2;FS=" ";$0=$0;print $2}'

在这里插入图片描述
案例4:读取.repo配置文件中的某段
本例选取yum源的配置文件CentOS-Base.repo作为实验素材,原文如下:

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the 
# remarked out baseurl= line instead.
#
#
 
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
        http://mirrors.aliyuncs.com/centos/$releasever/os/$basearch/
        http://mirrors.cloud.aliyuncs.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#released updates 
[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
        http://mirrors.aliyuncs.com/centos/$releasever/updates/$basearch/
        http://mirrors.cloud.aliyuncs.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
        http://mirrors.aliyuncs.com/centos/$releasever/extras/$basearch/
        http://mirrors.cloud.aliyuncs.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
        http://mirrors.aliyuncs.com/centos/$releasever/centosplus/$basearch/
        http://mirrors.cloud.aliyuncs.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/
        http://mirrors.aliyuncs.com/centos/$releasever/contrib/$basearch/
        http://mirrors.cloud.aliyuncs.com/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

假设现在要取出[base]段的文本,首先创建一个名为test1.awk的文件,然后编写脚本

[root@localhost yum.repos.d]# touch test1.awk
[root@localhost yum.repos.d]# ls
CentOS-Base.repo  CentOS-SCLo-scl-rh.repo  test1.awk

正则中需要转义的特殊字符如下:

$     匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n' 或 ‘\r'。要匹配 $ 字符本身,请使用 \$

( )    标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( 和 \)

*      匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*

+      匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+

.      匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \

[ ]    标记一个中括号表达式的开始。要匹配 [,请使用 \[

?      匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?

\      将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n' 匹配字符 ‘n'。'\n' 匹配换行符。序列 ‘\\' 匹配 “\”,而 ‘\(' 则匹配 “(”

^      匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^。

{ }    标记限定符表达式的开始。要匹配 {,请使用 \{

|      指明两项之间的一个选择。要匹配 |,请使用 \|
#/\[base\]/      字符不确定的情况下使用这种方法
#字符确定的情况下使用index
#对于确定字符串可以使用index进行搜索,在$0中进行搜索,当其中的字串存在[base]时候,返回其索引位,索引位是大于零的,从1开始
index($0,"[base]"){              
print
while( (getline var) >0 ){
if (var ~ /\[.*\]/){
  exit
	}
print var
  }
}
#getline()的说明
#当getline()的返回值大于零时,表示已经取到数据
#当getline()的返回值等于零时,表示遇到结尾EOF,也就是没有读取到符合条件的字符
#当getline()的返回值小于零时,表示读取报错,没有权限等
#var ~ /\[.*\]/  如果匹配到其他的就退出

在这里插入图片描述
在这里插入图片描述

案列5:根据某个字段去重
去掉 uid=xxx 重复的行
可以根据第一次出现去重,也可以根据最后一次出现去重

2019-01-13_12:00_index?uid=123
2019-01-13_13:00_index?uid=123
2019-01-13_14:00_index?uid=333
2019-01-13_15:00_index?uid=9710
2019-01-14_12:00_index?uid=123
2019-01-14_13:00_index?uid=123
2019-01-15_14:00_index?uid=333
2019-01-16_15:00_index?uid=9710

先将每一行以问号为界限划分为两个字段,然后将$2放入数组arr,统计$2出现的次数,如果只出现一次则输出,如出现多次只输出第一次出现的值

#awk -F "?" '{arr[$2]=arr[$2]+1;if(arr[$2]==1){print}}' test2.txt

也可以改为自增运算:

#awk -F "?" '{arr[$2]++;if(arr[$2]==1){print}}' test2.txt
或者
#awk -F "?" '{++arr[$2];if(arr[$2]==1){print}}' test2.txt

更进一步改进:

#awk -F "?" '!arr[$2]++{print}' test2.txt    
#当第一次读取到时arr[0]返回0,取反后返回为真,则输出;第二次读取到时,返回1,取反后为假,则不输出
#而且print也可以省略,因为awk默认会输出
#awk -F "?" '!arr[$2]++' test2.txt 

在这里插入图片描述

案列6:用awk数组做次数统计
(1)次数统计
统计的素材如下:

portmapper
portmapper
portmapper
portmapper
portmapper
portmapper
status
status
mountd
mountd
mountd
mountd
mountd
mountd
nfs
nfs
nfs_acl
nfs
nfs
nfs_acl
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr
#awk '{arr[$0]++}END{OFS="\t";for(i in arr){print arr[i],i}}' test3.txt

在这里插入图片描述
(2)统计TCP连接状态数量

#netstat -tnap

状态state字段是$6,将其放入数组中进行统计

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 192.168.33.99:25        0.0.0.0:*               LISTEN      2388/master         
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      2388/master         
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN      3313/sshd: root@pts 
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      1114/redis-server 1 
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      1726/rpcbind        
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1595/sshd           
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      2957/cupsd          
tcp        0      0 0.0.0.0:52856           0.0.0.0:*               LISTEN      1816/rpc.statd      
tcp        0      0 192.168.33.99:22        192.168.33.102:52093    ESTABLISHED 3313/sshd: root@pts 
tcp6       0      0 ::1:25                  :::*                    LISTEN      2388/master         
tcp6       0      0 ::1:6010                :::*                    LISTEN      3313/sshd: root@pts 
tcp6       0      0 :::42719                :::*                    LISTEN      1816/rpc.statd      
tcp6       0      0 :::111                  :::*                    LISTEN      1726/rpcbind        
tcp6       0      0 :::22                   :::*                    LISTEN      1595/sshd           
tcp6       0      0 ::1:631                 :::*                    LISTEN      2957/cupsd          
#netstat -nat|awk '/^tcp /{arr[$6]++}END{for(state in arr){print arr[state]":"state}}'

在这里插入图片描述

#netstat -nat | grep  'tcp' | awk '{print $6}'|sort | uniq -c

在这里插入图片描述
案列6:统计日志中特定条件的字段出现的次数

(1)统计日志中非200状态码的IP出现的次数

#awk '$8!=200{arr[$1]++}END{for(i in arr){print arr[i],i}}' access.log

在这里插入图片描述
进一步统计出现次数排名前十的IP:

#awk '$8!=200{arr[$1]++}END{for(i in arr){print arr[i],i}}' access.log | sort -k1nr | head -n 10

在这里插入图片描述
另外一种实现统计前十的 方法:

#awk '$8!=200{arr[$1]++}END{PROCINFO["sorted_in"]="@val_num_desc";for(i in arr){if(cnt++==10){exit}print arr[i],i}}' access.log

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章